Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 08:41 28 Nov 2024 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : Split string to substrings

Author Message
panky

Guru

Joined: 02/10/2012
Location: Australia
Posts: 1101
Posted: 08:25pm 12 Aug 2013
Copy link to clipboard 
Print this post

Hi All,

I had a need to parse an incoming string of characters delimited (in my case) with commas into substrings. In dr Basic! on the Android tablet I have, there is a split function that creates an array holding all the substring elements so I thought I would have a go at an MMBasic subroutine to do the same thing.

Hope it may be of some use to someone. It will take an arbitrary length (up to 255 characters long) string and break it up into substrings based on a user defined single character delimiter.

This code has the advantage of making use of Geoff's new feature in string arrays of defining element length to save space.


' Subroutine to split a delimited string of characters into individual
' substrings and return those substrings in a string array.
' As you can't pass arrays in MM Basic, the returned array will always
' be named splitup$()
' The program automatically calculates the number of substrings in the string
' and the size of the largest substring, then scales the array accordingly.
' The number of substrings is returned in array position 0 and the maximum
' length of each substring is returned in array position 1

Print "Testing code for split$ subroutine"
Print
Print "Test string is 'abc,defg,hijkl,+123.678,-5' with comma delimiter"
a$="abc,defg,hijkl,+123.678,-5"
Print "Usage is SPLIT$ arg$,delimiter$"

split$ a$,","

Print "The splitup array that is created is a one dimensional array that is "
Print "the number of substrings in the argument string + 2 in depth, "
Print "each of which equals the largest substring in characters long"
Print "Splitup$(0) has the number of substrings extracted in it"
Print "Splitup$(1) is the maximum string length of any substring"
Print "Splitup$(2) through Splitup$(n) contain the delimited substrings"
Print " of the argument string"
Print
Print "Test run"
Print "First substring of argument string at position 2 is ",splitup$(2)
Print "second substring of argument string at position 3 is ",splitup$(3)
Print "Third substring of argument string at position 4 is ",splitup$(4)
Print "Fourth substring of argument string at position 5 is ",splitup$(5)
Print "Fifth substring of argument string at position 6 is ",splitup$(6)
' End of test code

' SPLIT subroutine
Sub split$(arg1$,arg2$)
' arg1$ is the string to be split
' arg2$ is the delimiter to split on
Local whole$,delim$
Local numels,maxlen,wholelen,ellen
whole$=arg1$
delim$=arg2$
If Instr(whole$,delim$) <> 0 Then
numels = 1 ' delimiter found
maxlen = 1
Do While Instr(whole$,delim$) <> 0 ' now count up elements
ellen = Instr(whole$,delim$)-1 ' and maximum size so we
If ellen > maxlen Then
maxlen = ellen ' can dimension array
EndIf
numels = numels + 1
wholelen = Len(whole$)
whole$ = Right$(whole$,wholelen-(ellen + 1))
Loop
If Len(whole$) > maxlen Then
maxlen = Len(whole$)
EndIf

whole$ = arg1$
Dim splitup$(numels+2) length maxlen
splitup$(0) = Str$(numels)
splitup$(1) = Str$(maxlen)
For x = 2 To numels+1
wholelen = Len(whole$)
If x = numels+1 Then
ellen = Len(whole$)
splitup$(x) = whole$
Else
ellen = Instr(whole$,delim$) - 1
splitup$(x)=Left$(whole$,ellen)
whole$ = Right$(whole$,wholelen-(ellen+1))
EndIf
Next x
Else
Print "Error: No delimiter in string"
EndIf
End Sub


Cheers, Doug.

PS. Happy to have in the library Hugh if you think worthwhile.

... almost all of the Maximites, the MicromMites, the MM Extremes, the ArmMites, the PicoMite and loving it!
 
Blackened

Regular Member

Joined: 11/08/2012
Location: Australia
Posts: 66
Posted: 05:28am 13 Aug 2013
Copy link to clipboard 
Print this post

Thanks for sharing Panky

Well, I for one have a direct application for this routine. This will save me some time when I upgrade my brewing software. I'm in the middle of writing a menu to allow assorted data to be saved as CSV. Then the control software will open the file and use the data.

That's another wheel that I don't have to re-invent!
 
panky

Guru

Joined: 02/10/2012
Location: Australia
Posts: 1101
Posted: 09:22pm 13 Aug 2013
Copy link to clipboard 
Print this post

In my testing/usage, found a bug/limitation. As you can not re-dimension an existing array, there needs to be a erase statement immediatly before the dim statement in the code above.
...
...
Erase splitup$
Dim splitup$(numels+2) length maxlen
...
...

Now there is a new problem in that the first time you call split$, it will complain about erasing a variable that does not exist!!! So, befor calling SPLIT$ the first time you need to create the array with dummy parameters eg. Dim splitup$(1) then call the subroutine. Inside the subroutine the dummy will be erased prior to dimensioning.

Doug.
... almost all of the Maximites, the MicromMites, the MM Extremes, the ArmMites, the PicoMite and loving it!
 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 12:18am 14 Aug 2013
Copy link to clipboard 
Print this post

Panky, nice use of the length keyword.
There are a few things that you can do to optimize it a little.

Instead of repeatedly taking the right part of whole$ you can save the position of the delimiter for the next time you use instr. The first argument of instr is a start position. The first time entering the loop this start position has to be 1.
If you then take the result of the instr you can substract this startposition to get the length.
It will be a bit faster as no manipulation of the whole$ is needed.

I would like to see a result when no delimiters are found because it is still a valid condition in many cases. The program that uses the Split function should determine if it is an error. It will make the Split function more robust.

I would also suggest using a FUNCTION that returns the number of elements and only put results in the array.
You can then use it like this:
[code]
A = Split("This is a string to split into words", " ")
Print "There are " A " words."
for Index = 1 to A - 1
Print A;" ";SplitValues$(Index)
next
[/code]
The function can then for this example return 8 and the SplitValues$ contains the words in element 0 to 7;
Leaves you only without knowledge of the maximum length. I have never seen a split function that has that available so i guess you can skip it.
If that value is really necessary you can exploit the fact that parameters are passed by reference.
[code]
MaxLength = 0
A = Split("This is a string to split into words", " ", MaxLength)
Print "There are " A " words. Maxlength is " MaxLength
for Index = 1 to A - 1
Print A;" ";SplitValues$(Index)
next
[/code]
Edited by TZAdvantage 2013-08-15
Microblocks. Build with logic.
 
paceman
Guru

Joined: 07/10/2011
Location: Australia
Posts: 1329
Posted: 07:54pm 14 Aug 2013
Copy link to clipboard 
Print this post

Panky/TZ,

"SmallBasic" also has a function that does this. I haven't had cause to use it yet but I'll bet I will in future. Nice job!

Greg
 
shoebuckle
Senior Member

Joined: 21/01/2012
Location: Australia
Posts: 189
Posted: 09:45pm 14 Aug 2013
Copy link to clipboard 
Print this post

Doug,
I have added the Erase Splitup$ and was about to add Split$ to the library but thought you might like a chance to incorporate TZ's mods, if you like them.

Using your Sub format, rather than TZ's Function suggestion, you could pass back the number of elements and maximum length by reference. The user would have the option to leave them out of the calling statement if not required.

Split$ Source$,Delim$,Elements,MaxElLen
...
Split$ Source$,Delim$ 'Not interested in number of elements and length this time.
...

Sub Split$(arg1$,arg2$,numels,maxlen)
...
End Sub


You would,of course, need to remove numels and maxlen from the Local list as they are now defined as local by default in the Sub statement.
Cheers,
Hugh
 
panky

Guru

Joined: 02/10/2012
Location: Australia
Posts: 1101
Posted: 02:50pm 15 Aug 2013
Copy link to clipboard 
Print this post

TZ/Hugh,

Thanks for the feedback, both great ideas - I will try to incorporate and post an update,

Cheers, Doug.

... almost all of the Maximites, the MicromMites, the MM Extremes, the ArmMites, the PicoMite and loving it!
 
Print this page


To reply to this topic, you need to log in.

© JAQ Software 2024