[Implemented] More Flexable Version of FindString
[Implemented] More Flexable Version of FindString
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$
has-been wanna-be (You may not agree with what I say, but it will make you think).
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 ...
... 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.
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.
has-been wanna-be (You may not agree with what I say, but it will make you think).
@TrondTrond 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) ...
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)
What do you think?
cu, helpy
Wait! A whole new concept!
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))
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))
has-been wanna-be (You may not agree with what I say, but it will make you think).
I made the following test:
It will not work ... because the line:will be replaced by
And this results in the following error:
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
Code: Select all
test = FindStringEx("abcdef","c",StartPos,CaseSensitive,StopPos)
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
cu, helpyError: Line 21 - A variable can't be named the same as a PureBasic keyword: CompilerIf
at line 1 of the expanded macro (Macro.out)
Changed the test to:
This results in the following error:
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
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
Code: Select all
Error: Line 21 - Integer constant expression expected for compiler directives
at line 2 of the expanded macro (Macro.out)
This indeed is logical !!
cu, helpy
Look here for more informations about the "CompilerIf and macro"-problem:helpy wrote:This indeed is logical !!
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")
Code: Select all
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
Macro FunctionCall
CallFunction
EndMacro
CompilerElse
Macro FunctionCall
CallCFunction
EndMacro
CompilerEndIf
FunctionCall(1, "test")
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!Lebostein wrote:Macros allowed inside CompilerIF constructions only.
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