Page 1 of 1
[Implemented] More Flexable Version of FindString
Posted: Mon Mar 27, 2006 6:58 am
by oldefoxx
Without breaking with current FindString() syntax, I would like to see two added capabilities: (1) the ability to have a case-insensitive search for string matches, and (2) the addition of an optional paramter to limit the search range within the parameter String$. A zero means no limit, except the length of String$. any other value means stop at that point if within the length of String$
Posted: Mon Mar 27, 2006 3:36 pm
by Trond
I haven't tested it but maybe you can use something like this while you are waiting:
Code: Select all
Macro FindStringEx(String, StringToFind, StartPos, CaseSensitive = 0, StopPos = 0)
CompilerIf CaseSensitive
CompilerIf StopPos > 0
FindString(UCase(String), UCase(Left(StringToFind, StopPos)), StartPos)
CompilerElse
FindString(UCase(String), UCase(StringToFind), StartPos)
CompilerEndIf
CompilerElse
CompilerIf StopPos > 0
FindString(String, Left(StringToFind, StopPos), StartPos)
CompilerElse
FindString(String, StringToFind, StartPos)
CompilerEndIf
CompilerEndIf
EndMacro
Thanks, but here is the problem ...
Posted: Mon Mar 27, 2006 5:17 pm
by oldefoxx
... This could be a help to others, might even convince some people that my request is not really needed. But the Problem with using Mid(), Left(), Right(). UCase(), and LCase() in this manner is that they result in temporary strings, and creating temporary strings cause a lot more processing time to be invloved,
So this is an area that can really be enhanced with optimized code, that can process strings in place, and that is why I brought it up. It is certainly possible to write equivalent functionality in ASM, PB syntax, or a combination of the two, or even with a Macro as you illustrated, but it occurred to me that it would be a worthy addition to the PB syntax. It would create one of the most adaptive FindSrting() implementations around.
Though it would still lack the reverse search sequence (searching right to left) that PowerBasic uses with its INSTR() function. It does this by using a negative value for the offset to indicate processing from the right. So a -1 would mean "Start processing with the first character of String$ from the right". But I don't thinkg that the PowerBasic use recognizes that if you are searching for a five character StringToFind$, that you don't want to actually start with -1 when searching from the right, you want to start with -Len(FindToString$), which is where the first possible match could possibly occur?
So the BP implementation could be made that much smarter and faster -- maybe. Only problem is that after your first match, say when right-to-left searching "AAA" in a series of "AAAAAAAAAAAAAAAAA", should the second match be at -4, or -6? The right answer is that going in reverse in this manner should work exactly the opposite as going in the present directon, so that the transposition is merely in the use of a sign flag for the offset. But the underlying seach mechanism could be just a tad smarter to make sure we don't end up performing useless cycles.
Posted: Mon Mar 27, 2006 5:26 pm
by helpy
Trond wrote:I haven't tested it but maybe you can use something like this while you are waiting:
Code: Select all
Macro FindStringEx(String, StringToFind, StartPos, CaseSensitive = 0, StopPos = 0)
...
@Trond
do you know what happens, if CaseSensitive and StopPos are variables? At compile time the compiler does not know, which value the variables will have! But I think it is different to the default value "0".
If the compiler handles variables different to "0" then the result of CaseSensitive=variable and StopPos=variable will be:
Code: Select all
FindString(UCase(String), UCase(Left(StringToFind, StopPos)), StartPos)
I didn't make the test.
What do you think?
cu, helpy
Posted: Mon Mar 27, 2006 6:23 pm
by Trond
No idea at all. :roll:
Wait! A whole new concept!
Posted: Mon Mar 27, 2006 6:48 pm
by oldefoxx
PowerBasic uses a keyword ANY with some string commands, so if I say
a = INSTR(String$, ANY "1234567890"), I mean search until you find any one of those characters in String$.
Not that I am trying to steal PowerBasic's thunder, but I think ANY could be used much more effectively. Instead of just a compiler directive, what if ANY became a directive and a function in its own right? So that if I say Print( Any(2, "ALAKASAZARCACOCTDEDCFMFLGAGUHIIDILINIAKSKYLAMEMHMDMAMIMNMSMOMTNENHNJNMNYNCNDMPOHOKPWPAPRRISCSDTNTXUTVTVIVAWAWVWIWY"))
It would mean to repeat a process, returning two characters each time, until it finally returnes null characters (""). In the example above, I have most of the postal codes used by the US Post Office.
Or I could say Offset = FinstString(Text$, ANY(3, "JANFEBMARAPRMAYJUNJULAUGOCTNOVDEC"), 1) and try to search for a matching month. Or I could say Offset = FindString( Text$, ANY(3, "SunMonTueWedThuFriSat"), 1) to try and find a matching day. Or I could be more restricting and say Offset=FindString(Text$," " + ANY(3, "SunMonTueWedThuFriSat"), 1), or a=FindString(Text$, Any(4, " Sun Mon Tue Wed Thu Fri Sat Sun"), 1), or even get really creative and say:
DateDay=FindString(Text$, Any " " + ANY(3, "JanFebMarAprMayJunJulAugOctNovDecSunMonTueWedThuFriSat"), 1) to see if I can find any text where it appears that a date or day may be specified.
Not to say that ANY() would be used by itself for text matches. Rather, it would work in conjunction with FindString, CountString, and StringField, Print, and other commands to repeat a given process that incrementally works through the string specified by ANY in increments that the user specifies, such as a=CountString(String$, index, Any(1, " ;:,.<>/?!@#$%^&*()-_=+[]{}"+Chr(13)+Chr(10)+Chr(9))
Posted: Mon Mar 27, 2006 6:56 pm
by helpy
I made the following test:
Code: Select all
Macro FindStringEx(String, StringToFind, StartPos, CaseSensitive = 0, StopPos = 0)
CompilerIf CaseSensitive
CompilerIf StopPos > 0
FindString(UCase(String), UCase(Left(StringToFind, StopPos)), StartPos)
CompilerElse
FindString(UCase(String), UCase(StringToFind), StartPos)
CompilerEndIf
CompilerElse
CompilerIf StopPos > 0
FindString(String, Left(StringToFind, StopPos), StartPos)
CompilerElse
FindString(String, StringToFind, StartPos)
CompilerEndIf
CompilerEndIf
EndMacro
StartPos = 0
CaseSensitive = 0
StopPos = 5
test = FindStringEx("abcdef","c",StartPos,CaseSensitive,StopPos)
Debug test
CaseSensitive = 1
test = FindStringEx("abcdef","c",StartPos,CaseSensitive,StopPos)
Debug test
It will not work ... because the line:
Code: Select all
test = FindStringEx("abcdef","c",StartPos,CaseSensitive,StopPos)
will be replaced by
Code: Select all
test = CompilerIf CaseSensitive
CompilerIf StopPos > 0
FindString(UCase("abcdef"), UCase(Left("c", StopPos)), StartPos)
CompilerElse
FindString(UCase("abcdef"), UCase("c"), StartPos)
CompilerEndIf
CompilerElse
CompilerIf StopPos > 0
FindString("abcdef", Left("c", StopPos), StartPos)
CompilerElse
FindString("abcdef", "c", StartPos)
CompilerEndIf
CompilerEndIf
And this results in the following error:
Error: Line 21 - A variable can't be named the same as a PureBasic keyword: CompilerIf
at line 1 of the expanded macro (Macro.out)
cu, helpy
Posted: Mon Mar 27, 2006 7:00 pm
by helpy
Changed the test to:
Code: Select all
Macro FindStringEx(Result,String, StringToFind, StartPos, CaseSensitive = 0, StopPos = 0)
CompilerIf CaseSensitive
CompilerIf StopPos > 0
Result = FindString(UCase(String), UCase(Left(StringToFind, StopPos)), StartPos)
CompilerElse
Result = FindString(UCase(String), UCase(StringToFind), StartPos)
CompilerEndIf
CompilerElse
CompilerIf StopPos > 0
Result = FindString(String, Left(StringToFind, StopPos), StartPos)
CompilerElse
Result = FindString(String, StringToFind, StartPos)
CompilerEndIf
CompilerEndIf
EndMacro
StartPos = 0
CaseSensitive = 0
StopPos = 5
FindStringEx(test,"abcdef","c",StartPos,CaseSensitive,StopPos)
Debug test
CaseSensitive = 1
test = FindStringEx(test,"abcdef","c",StartPos,CaseSensitive,StopPos)
Debug test
This results in the following error:
Code: Select all
Error: Line 21 - Integer constant expression expected for compiler directives
at line 2 of the expanded macro (Macro.out)
That means, that if macro parameters are used in CompilerIf expressions, they have to be numerical constants. It is not allowed to pass variables to CompilerIf statement.
This indeed is logical !!
cu, helpy
Posted: Tue Mar 28, 2006 7:10 am
by Lebostein
helpy wrote:This indeed is logical !!
Look here for more informations about the "CompilerIf and macro"-problem:
http://www.purebasic.fr/english/viewtop ... 243#134243
Macros allowed inside CompilerIF constructions only. Look at this example:
Problem: CompilerIf inside macro
Code: Select all
Macro FunctionCall
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
CallFunction
CompilerElse
CallCFunction
CompilerEndIf
EndMacro
FunctionCall(1, "test")
Solution: macro inside CompilerIf
Code: Select all
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
Macro FunctionCall
CallFunction
EndMacro
CompilerElse
Macro FunctionCall
CallCFunction
EndMacro
CompilerEndIf
FunctionCall(1, "test")
Posted: Tue Mar 28, 2006 8:54 am
by helpy
Lebostein wrote:Macros allowed inside CompilerIF constructions only.
Does that mean, that CompilerIf is not allowed inside macros? That would be bad, if future compiler versions would reject the use of CompilerIf inside macros!
I use CompilerIf statements inside macros to check the previous use of other macros. For instance:
Code: Select all
Macro DQ
"
EndMacro
Macro _MakeString(s)
DQ#s#DQ
EndMacro
Macro TEST_START(Name)
CompilerIf Defined(__TEST__#Name#__TEST__,#PB_Constant)
CompilerError "TEST1: <" + _MakeString(Name) + "> is already in use!"
CompilerElse
#__TEST__#Name#__TEST__ = #True
CompilerEndIf
; some other things doing with "Name"
EndMacro
Macro TEST_END(Name)
CompilerIf Defined(__TEST__#Name#__TEST__,#PB_Constant) = 0
CompilerError "TEST2: <" + _MakeString(Name) + "> was not used with TEST1!"
CompilerEndIf
; some other things doing with "Name"
EndMacro
TEST_START(test1)
; doing other stuff in the context of "test1)
TEST_END(test1)
;TEST_START(test1) ; will cause a compile error
;TEST_END(test2) ; will cause a compile error
Posted: Tue Mar 28, 2006 11:24 am
by freak
CompilerIf works inside macros without problem. It just does not work with a variable, which makes sense.