; Stores all words in w
Global Dim w.s(0)
Procedure CountSep(str.s,sep.s)
o_si=1
For si=1 To Len(str)
sc.s=Mid(str,si,1)
If in_str.s="" And (sc="'" Or sc=Chr(34))
in_str=sc
ElseIf sc=in_str
in_str=""
EndIf
If in_str=""
For i=1 To Len(sep)
c.s=Mid(sep,i,1)
If c=sc
word.s=Mid(str,o_si,si-o_si)
If word<>""
wi+1
EndIf
wi+1
o_si=si+1
EndIf
Next
EndIf
Next
word=Mid(str,o_si,Len(str))
If word<>""
wi+1
EndIf
ProcedureReturn wi
EndProcedure
Procedure Split(str.s,sep.s)
o_si=1
For si=1 To Len(str)
sc.s=Mid(str,si,1)
If in_str.s="" And (sc="'" Or sc=Chr(34))
in_str=sc
ElseIf sc=in_str
in_str=""
EndIf
If in_str=""
For i=1 To Len(sep)
c.s=Mid(sep,i,1)
If c=sc
word.s=Mid(str,o_si,si-o_si)
If word<>""
w(wi)=word
wi+1
EndIf
w(wi)=c
wi+1
o_si=si+1
EndIf
Next
EndIf
Next
word=Mid(str,o_si,Len(str))
If word<>""
w(wi)=word
wi+1
EndIf
ProcedureReturn wi
EndProcedure
ret=CountSep(str, sep) is used to count the separations in str. Returns the total number of words for reDim'ng w with.
ret=Split(str, sep) just like CountSep but actually stores the words and separators in w().
'str' the string to split up.
'sep' is a string holding the separator(s).
'ret' is number of words including separators.
'w()' array of words and separators.
*strings in 'str' beginning and ending with ' or " are preserved.
Is it possible to go a step further and do something like:
1. Have one command Split.
2. Pass an additional param to the sub, such as an Array, or an pointer to an array.
3. Have the routine clear the array (just in case), redim it to whatever number there is, and fill in the values?
4. Then have it either return the array or, not, as the array is globle, I thought. But this way, people can do pass different arrays at different times.
Shannara wrote:Is it possible to go a step further and do something like:
1. Have one command Split.
2. Pass an additional param to the sub, such as an Array, or an pointer to an array.
3. Have the routine clear the array (just in case), redim it to whatever number there is, and fill in the values?
4. Then have it either return the array or, not, as the array is globle, I thought. But this way, people can do pass different arrays at different times.
1. Yes, but it will conflict with your other requests.
2. A pointer would be possible, but for the array I've never seen how to pass one to a procedure.
3. Since the array is global that would be easy, although a pointer I wouldn't know how to pass one to Dim.
4. This suffers the same problems as 2.
Arrays are normally passed by pointer reference, which shows where the
array is in memory, but it means that the procedure you are calling has to
expect this. You can't pass an array by pointer if the procedure is set up
to expect something different.
Let's see if I can explain this a little better, without passing myself off as
expert in this area:
When you see a prototype (you declare a procedure with the parameter
information that exists in some library or is internal to the program),
and you are indicating that you are passing a structure or type, what
happens is that you are merely telling the compiler the structure (or
TYPEDEF) that pointer is going to be for. That gives the compiler the
ability to verify that the actual structure or array passed agrees with the
prototype. Of course if the prototype is for an internal procedure, the
prototype is optional, but it does give the compiler more things to verify.
The prototype needs to match the parameters required by the procedure.
You can't get too inventive in this area. Sometimes you can pass one
32-bit type in place of another by the way you set up the prototype.
But the number of parameters, and the size of each of the parameters,
must match with the actual procedure.
If you pass a String, you are actually passing a pointer to the head of
that string. It will be a Null-terminated string. If the first character in
the screen is a Null character, it will be an empty string. If the pointer
value is zero, the string has not been defined yet, and we refer to
this as a Null string. To see if a null string reference was passed, you
need to check the pointer value to see if it is zero. That means
treating the passed value as a number. If it is not zero, then it points
to a string, so we have to recast the value passed as a string pointer
reference.
The same MAY hold true for passing an array reference. In other words,
since no pointer is valid if it has a zero value, the result is that you are
indicating that the array does not exist if the pointer=0. But to find
this out, you first have to treat the value passed as a number.
If you try to dereference a pointer when it has a value of zero, you will
be performing an illegal memory operation that will result in a GPF
(General Protection Fault) by the system. That means that if you use
a computer language to write the procedures, that language should
ideally check pointers before dereferencing them. If the pointers are
valid, the procedure then handles the dereferenced memory area as a
string, array, or whatever other structure it was expecting. If you pass
something that does not meet that expectation, you create a situation
where something unpredictable is going to happen - certainly nothing
that you want to happen. By checking for a Null (or pointer=0) first,
you can avoid the GPF and possibly finesse the situation by ignoring the
parameter altogether or working around it.
On the other hand, if you write a procedure in a language that does not
give you a way to verify if a NULL was passed, then you are at the
mercy of the programmer who writes the code to call the procedure.
The best you can do is advise them what types or structures need to
be passed, and that the procedure cannot handle NULL. It will be up
to them to make sure that the parameters passed are always defined.
If you are writing a procedure as a possible port to a library, such as a
DLL, to be used with other languages, you might want to consider the
matter another way as well: You may have a situation where your
procedures handle NULL situations without difficulty, but the program
language used to call your library may be incapable of passing one.
You might want to consider some way that they can pass something
that uniquely signifies a NULL situation is being implicated. An example
might be to pass a string like "]_[". For an array, you would have to
pass something would not be considered valid within that array. For
instance, if it calls for a last name, anything that could not possibly be
a valid last name would do the trick. Your procedure must of course
know what to look for, and that is part of the details that must be made
known to the programmer using your code.
I hope this is not overkill.
has-been wanna-be (You may not agree with what I say, but it will make you think).
So, the following should do the exact same as above but with less code (still not effecient though, I need to figure out a way to pass an array to a function )
dim w.s(0)
Procedure SplitMe(myString.s, SepString.s)
SepCount = CountString(myString,SepString) + 1
Dim w.s(SepCount-1)
For k=0 To SepCount-1
w(k) = StringField(myString, k+1, SepString)
Next
EndProcedure
dim w.s(0)
Procedure SplitMe(myString.s, SepString.s)
SepCount = CountString(myString,SepString) + 1
Dim w.s(SepCount-1)
For k=0 To SepCount-1
w(k) = StringField(myString, k+1, SepString)
Next
EndProcedure
I tried to convert the code generated by PB when compiling this into a lib.
It's partly succesfull. Here's a little zip file. It contains three files. The lib, the asm source and a test. Maybe someone with better asm knowledge can improve it or clean it up. I don't know of the release of the old array is working properly.
venom wrote:Not exactly the same, the original preserves string literals and supports multiple delimiters.
Oh, I didnt know the original supports more then one delimiter character... where would that be in the code ...?
In this one, this emulates the split function of VB exactly, except for the passing of the array. This also preserves the original passed string And supports as many delimiters instances that the string has.