SpaceFrog 09-08-2003, 06:43 AM What would be the best way to make a special split function that would return an array of caracters from a string grouping them by a specific count.
MyString="abcdefghi"
MyArray = SpecialSplit(MyString, 3) would return
Myarray(0) = "abc"
Myarray(1) = "efg"
etc ...
I have been looking at mid left right split and always end up in some messy code full of condition tests ...
There has to be as simple way of doing this ...
passel 09-08-2003, 06:48 AM My shot.
Dim p As Integer
a$ = "This is a test"
ReDim b(Len(a) \ 3)
For i = 1 To Len(a$) Step 3
b(p) = Mid$(a$, i, 3)
p = p + 1
Next
SpaceFrog 09-08-2003, 06:52 AM I was somewhere around there as well passel, but 3 was an example.
SpecialSplit(Mystring,GroupCount) would then need test such as
if GroupCount > len(MyString)...
And what about Len(Mystring) /GroupCount for the last item of array ...
passel 09-08-2003, 07:07 AM Well, do you want to pad? If so.
Dim p As Integer, locString As String
Dim grp As Integer
grp = 20
a$ = "This is a test"
locString = a$ & Space$(Len(a$) Mod grp)
ReDim b(Len(locString) \ grp)
For i = 1 To Len(locString) Step grp
b(p) = Mid$(locString, i, grp)
p = p + 1
Next
passel 09-08-2003, 07:16 AM Well, do you want to pad? If so.
Dim p As Integer, locString As String
Dim grp As Integer
grp = 20
a$ = "This is a test"
locString = a$ & Space$(Len(a$) Mod grp)
ReDim b(Len(locString) \ grp)
For i = 1 To Len(locString) Step grp
b(p) = Mid$(locString, i, grp)
p = p + 1
Next
Edit: Hey spacefrog, I'm testing this, and I already know there's a
problem with the Mod, I'll get back to you.
SpaceFrog 09-08-2003, 07:23 AM I was working with :
remainingstring = mystring
dowhile len (remainingstring)>=grp
Redim preserve MyArray(ubound(Myarray)+1)
MyArray(ubound(Myarray)) = left(mystring,grp)
RemainingString = right(Mystring, len(mystring) - grp)
loop
Redim preserve MyArray(ubound(Myarray)+1)
MyArray(ubound(Myarray)) = remainingstring
SpaceFrog 09-08-2003, 07:27 AM remainingstring = mystring
dowhile len (remainingstring)>=grp
ReDim Preserve MyArray(UBound(Myarray)+1)
MyArray(UBound(Myarray)) = left(mystring,grp)
RemainingString = right(Mystring, len(mystring) - grp)
Loop
if len(mystring - grp) > 0 then
ReDim Preserve MyArray(UBound(Myarray)+1)
MyArray(UBound(Myarray)) = remainingstring
end if
Not quite sure about the end bit ...
passel 09-08-2003, 07:33 AM Dim p As Integer, locString As String
Dim grp As Integer
grp = 15
a$ = "This is a test"
locString = a$ & Space$((grp - 1) - (Len(a$) + grp - 1) Mod grp)
ReDim b((Len(locString) \ grp) - 1)
For i = 1 To Len(locString) Step grp
b(p) = Mid$(locString, i, grp)
p = p + 1
Next
This works now. Before the mod wasn't adding the right number of
spaces in all cases, and the array had 1 more index than it needed.
SpaceFrog 09-08-2003, 07:38 AM The grp integer would be the group count...
I dont really understand the locstring variable...
How does your code work the whole thing out ?
passel 09-08-2003, 08:01 AM Here it is as a Subroutine. I'm not sure how to declare a funtion that
will return an array. I'll have to look that up, it must be possible?
Private Sub mysplit(st As String, grp As Integer, ar() As String)
Dim p As Integer, locString As String
locString = st & Space$((grp - 1) - (Len(st) + grp - 1) Mod grp)
ReDim ar((Len(locString) \ grp) - 1)
For i = 1 To Len(locString) Step grp
ar(p) = Mid$(locString, i, grp)
p = p + 1
Next
End Sub
Anyway,
The way locString works is essentially this
if locString's length is not a multiple of our desired group size, then we
want to add spaces to the end to bring it up to the end.
So if we do a mod on the length, we can find how how many characters
extra we currently have.
0, no extra characters,
1, 1 extra
2, 2 extra ...etc..
if the value is 0, we don't need to add anything otherwise,
we need to subtract the extra from the group, to see how many to add.
So the code would be easier to understand like this.
extra = Len(st) Mod grp
if extra = 0 then
locString = st
else
locString = st & Space$(grp - extra)
end if
But you can "shorten" the logic a little if you purposely add extra
characters "logically" and then trim off the excess. (in other words, since
you know you will always have to subtract characters, you can include
the 0 case without having to test it separately.
An example works best, but I've got to go to a meeting. I'll get back
with ya later.
SpaceFrog 09-08-2003, 08:24 AM Ok ! Got it I just could not figure out why you needed to add spaces to the string as I was stuck to applying mid to initial string and not modified one...
Thanks... It does works gr8 !
I'm still looking for a simpler way to do it direclty with some kind of strconv instruction (just for the fun of it)
BinaryMayhem 09-08-2003, 08:24 AM Here it is as a Subroutine. I'm not sure how to declare a funtion that will return an array. I'll have to look that up, it must be possible?
yes it is... you must declare the function as type variant and then store the results in a variable.
im not at home, so I don't have access to vb, but that's how it works.
I posted a simular solution here...
http://www.visualbasicforum.com/showthread.php?t=98581 (functions)
SpaceFrog 09-08-2003, 08:38 AM Function mysplit(st As String, grp As Integer ) as variant
Dim p As Integer, locString As String, ar() as string
locString = st & Space$((grp - 1) - (Len(st) + grp - 1) Mod grp)
ReDim ar((Len(locString) \ grp) - 1)
For i = 1 To Len(locString) Step grp
ar(p) = Mid$(locString, i, grp)
p = p + 1
Next
MySplit = ar
End Sub
Would be used :
dim FinalArray as variant
Dim TestString as string
TestString = "abcd e f r g d d f "
FinalArray = MySplit(TestString,3)
passel 09-08-2003, 09:32 AM Yes, I wasn't sure from your earlier comment whether you wanted the
LocString variable or not, so I created a different version that didn't
use locString. I'll modify what you have. I changed the integers to
long since they should be quicker.
Function Mysplit(st As String, grp As Long) As Variant
Dim p As Long, L As Long, ar() As String
L = Len(st) 'get the length of the input string
If L Mod grp Then 'dimension the output array
ReDim ar(L \ grp)
Else
ReDim ar((L \ grp) - 1)
End If
For i = 1 To L Step grp 'for each substring
ar(p) = Space$(grp) ' allocate a string in the array
Mid$(ar(p), 1) = Mid$(st, i, grp) ' insert the substring
p = p + 1 ' prepare for next substring
Next
Mysplit = ar
End Function
Thinker 09-08-2003, 09:38 AM If you know you are returning an array of strings don't use a
variant - use As String()
passel 09-08-2003, 10:06 AM If you know you are returning an array of strings don't use a
variant - use As String()
Well, I may be doing something wrong, but when I try this in VB 5.0
Function Mysplit(st As String, grp As Long) As String()
It turns red, indicating a syntax error. I couldn't figure out how to get
it to return an array without using a variant. Thinker, could you clarify where I'm in error?
I also get a compile time error (Can't assign to an array) if I try to
assign the return of the function to an array, so that end requires a
variant. The same is true with the built in Array function.
I can't try VB6 because I'm not at home.
Anyway, here's a slightly improved version of the last function. It
preadjusts the L value so you don't need the "If" and the two "ReDim" lines.
Function Mysplit(st As String, grp As Long) As Variant
Dim p As Long, L As Long, ar() As String
L = Len(st) + grp - 1 'These two lines Round Len of st up
L = L - L Mod grp 'to a multiple of Group
ReDim ar((L \ grp) - 1) 'Then dimension our output array to what we need
For i = 1 To L Step grp 'for each substring
ar(p) = Space$(grp) ' allocate the desired string len
Mid$(ar(p), 1) = Mid$(st, i, grp) ' insert the substring
p = p + 1 ' next index
Next
Mysplit = ar
End Function
Thinker 09-08-2003, 10:11 AM Yes true, that was added to VB6. I didn't see any mention of vb5 before.
passel 09-08-2003, 10:24 AM Yes true, that was added to VB6. I didn't see any mention of vb5 before.
Ok SpaceFrog, as Thinker says, if you are using VB6 (and I did get a
chance to try it on another machine that has Office 2000 on it, which in
this case, the code is the same in VBA as VB6) and it works. So I
whole-heartedly agree that it is better to use a dynamic String array
type for the function declaration.
SpaceFrog 09-09-2003, 12:51 AM Yes I am using VB6, that is why I had put as variant...
Thanks for all guys !
Looks like we will not get any better than that.
SpaceFrog 09-09-2003, 03:02 AM Stille exploring...
Ok guys here's a bezerk one :
Dim mystring$, n%
Dim myformat$,
mystring = "mkljdsfmlkfhfdhsdhdhdfhdfgdfgsgdjf"
n = 4
mystring = mystring + String((n - (Len(mystring) Mod n)), " ")
Dim mypatern$
Dim myarray As Variant
mypatern = String(n, "@") & " | "
myformat = ""
For i = 1 To (Len(mystring) / n) - 1
myformat = myformat & mypatern
Next
myformat = myformat & String(n, "@")
myarray = Split(Format(mystring, myformat), "|")
I don't like the concataining of format with a for next loop
I tried with string(number,char) but it only take one char into account ...
passel 09-09-2003, 08:30 AM I'm not sure why you have spaces around the "|" when you create the
format, and then split it without the spaces. This would seem to make your
first word in the array 5 characters, with a trailing space, each of the
intermediate strings 6 characters, with a leading and trailing space, and
the last string 5 characters, with a leading space.
Don't have VB6 available at the moment so can't test the split, but that
is what I would expect.
It would be better to insert into a string, rather than append to a string
when creating your pattern. And I think using space$, is better than
string$ when creating a string of spaces (although I haven't tested it, to
see if it's "better").
So, not knowing if there is a reason for the split pattern being different,
I just modified it so that you can specify the split pattern in one place
and insert the split pattern into a string of the "background" @'s.
'
Dim mystring$, n%, np%, c%, L%
Dim myformat$, mydelimiter$
mystring = "mkljdsfmlkfhfdhsdhdhdfhdfgdfgsgdjf"
mydelimiter = "|"
n = 4
L = Len(mydelimiter)
np = n + L
mystring = mystring + Space$(n - (Len(mystring) Mod n))
c = Len(mystring) \ n
myformat = String$((np * c) - L, "@")
p = n + 1
For i = 1 To c - 1
Mid$(myformat, p) = mydelimiter
p = p + np
Next
myarray = Split(Format(mystring, myformat), mydelimiter)
I can't believe that this is quicker than the approach we took earlier, but
is yet another way to solve the problem.
passel 09-09-2003, 08:33 AM Yes I am using VB6, that is why I had put as variant...
Thanks for all guys !
Looks like we will not get any better than that.
And it sounds like you mis-read Thinker and me. If you are using VB6
then you can use String(), instead of Variant, which should make the
function a little faster (returning a string instead of a variant).
SpaceFrog 09-09-2003, 08:51 AM Ok Passel,
Exact, I had encountered difficulties with the pipe and space sequence, and in my final code the pipe is no more surrounded by spaces ...
And for the string bit, yes I did miss that one, trying speed reading on a screen in a foreign language is not that easy ;-), I set it to string and it does work...
Haven't tested it for speed, but juste tying to find differnt ways before launching test speed on large strings...
|