Page 1 of 2

an equal '=' test string not case sensitive

Posted: Wed Jul 24, 2013 2:41 am
by said
would be really nice to be able to test 2 strings regardless of their case.

An idea, this could be achieved via a new directive such as

EnableTextCompare

then all s1$ = s2$ will compare the two strings with no case and then we dont need a new operator for that

For now i have to convert both strings into lower/upper casing and compare!

Hope you find this useful

Re: an equal '=' test string not case sensitive

Posted: Wed Jul 24, 2013 3:18 am
by TI-994A
said wrote:...all s1$ = s2$ will compare the two strings with no case and then we dont need a new operator for that

For now i have to convert both strings into lower/upper casing and compare!
Hello said. For now, instead of converting the strings to match their cases, perhaps you could make use of PureBasic's FindString() function with the #PB_String_NoCase flag, like this:

Code: Select all

s1$ = "hello said!"
s2$ = "HELLO Said!"
If FindString(s1$, s2$, 1, #PB_String_NoCase)
  result$ = "The two strings match!"
Else
  result$ = "The two strings don't match."
EndIf
MessageRequester("Case Insensitive String Compare", result$)
Just a suggestion. :)

Re: an equal '=' test string not case sensitive

Posted: Wed Jul 24, 2013 4:28 am
by Demivec
Or using CompareMemoryString():

Code: Select all

s1$ = "hello said!"
s2$ = "HELLO Said!"
If CompareMemoryString(@s1$, @s2$, #PB_String_NoCase) = #PB_String_Equal
  result$ = "The two strings match!"
Else
  result$ = "The two strings don't match."
EndIf
MessageRequester("Case Insensitive String Compare", result$)

Re: an equal '=' test string not case sensitive

Posted: Wed Jul 24, 2013 4:39 am
by skywalk

Code: Select all

Macro StrCmp(str1, str2, UseCase=#PB_String_NoCase)
  Bool(CompareMemoryString(@str1, @str2, UseCase) = #PB_String_Equal) ; = 0 means same memory
EndMacro
s1$ = "hello said!"
s2$ = "HELLO Said!"
If StrCmp(s1$,s2$)  ; ,#PB_String_CaseSensitive)
  MessageRequester("String Compare", "Match")
Else
  MessageRequester("String Compare", "No Match")
EndIf
EDIT: Demivec beat me :oops:

Re: an equal '=' test string not case sensitive

Posted: Wed Jul 24, 2013 9:01 am
by Michael Vogel
Or keep the simple If LCase(a$)=LCase(b$), if speed is not the primary target...

Re: an equal '=' test string not case sensitive

Posted: Wed Jul 24, 2013 10:23 am
by said
thank you all for your suggestions, nice ones (honestly, never thought of using a FindString for that :shock: TI-994A :!: )

My thought, this is a basic test that we are likely to use everyday and in almost any program!

Re: an equal '=' test string not case sensitive

Posted: Sat Jul 27, 2013 11:47 am
by said
After doing some tests:

using CompareMemoryString() as suggested by Demivec, skywalk ... this cannot be used when one param is a constant string ( #txt$ = "hello SaiD" ) even after converting the macro into a procedure and using a local variable to receive the param! Looks like PB treats very differently constant-strings and variable-strings!

using FindString() as suggested by TI-994A is on avg 6-7 times slower than UCase() /LCase() ...

for me this feature request still makes sense!

Re: an equal '=' test string not case sensitive

Posted: Sat Jul 27, 2013 12:09 pm
by Little John
said wrote:using FindString() as suggested by TI-994A is on avg 6-7 times slower than UCase() /LCase() ...
Then just use UCase() /LCase(). :-)

Re: an equal '=' test string not case sensitive

Posted: Sat Jul 27, 2013 2:31 pm
by said
Little John wrote: Then just use UCase() /LCase(). :-)

am using it right now :D (see first post) however i believe if implemented native in PB the test would be much faster

Re: an equal '=' test string not case sensitive

Posted: Sat Jul 27, 2013 4:18 pm
by Demivec
said wrote:After doing some tests:

using CompareMemoryString() as suggested by Demivec, skywalk ... this cannot be used when one param is a constant string ( #txt$ = "hello SaiD" ) even after converting the macro into a procedure and using a local variable to receive the param! Looks like PB treats very differently constant-strings and variable-strings!

using FindString() as suggested by TI-994A is on avg 6-7 times slower than UCase() /LCase() ...

for me this feature request still makes sense!
There's other ways of doing it, that may or not be feasible for your particular needs. Just for the sake of comparison, here's a way that requires you to define constants differently:

Code: Select all

#txt$ = "hello SaiD!"
DataSection
  c_txt$: Data.s #txt$ ;constant
EndDataSection

Macro StrCmp(str1, str2, UseCase=#PB_String_NoCase)
  Bool(CompareMemoryString(@str1, @str2, UseCase) = #PB_String_Equal) 
EndMacro

Macro StrCmp_c(str1, str2, UseCase=#PB_String_NoCase)
  Bool(CompareMemoryString(@str1, ?str2, UseCase) = #PB_String_Equal) 
EndMacro

s1$ = "hello said!"
s2$ = "HELLO Said!"

Debug StrCmp_c(s1$, c_txt$)
Debug StrCmp_c(s2$, c_txt$)
Debug StrCmp(s1$, s2$)
Debug StrCmp(s1$, s2$, #PB_String_CaseSensitive) 
You'll notice that you have to use a different macro to specifically handle when you are using the constants that have been declared this way.

I get a 10x speedup over using UCase()/LCase() when doing it this way.

Not being able to retrieve the address of a literal string or a string constant definitely throws curves into the process. I agree that the easiest thing to do is probably just to continue on with UCase/LCase() until a native solution is reached. :)

Re: an equal '=' test string not case sensitive

Posted: Sat Jul 27, 2013 5:06 pm
by skywalk
If you really want to speed up the comparison, just drop the String Constant since they cannot be addressed using @.
In these cases I use a global string variable instead.

Re: an equal '=' test string not case sensitive

Posted: Sat Jul 27, 2013 5:36 pm
by said
Demivec wrote: .... just to continue on with UCase/LCase() until a native solution is reached. :)
I think i will continue that way ... Thanks for trying to find workarounds :!: still quite cumbersome and requires knowing before hand that we are to deal with literal string ...

However we are in the Feature Requests section and this is just one of them ... Hopefully the PB team will think this is an important one and decide to implement it :!:

Re: an equal '=' test string not case sensitive

Posted: Sat Jul 27, 2013 6:05 pm
by TI-994A
said wrote:using CompareMemoryString() ... cannot be used when one param is a constant string ( #txt$ = "hello SaiD" ) even after converting the macro into a procedure and using a local variable to receive the param! ...

using FindString() ... is on avg 6-7 times slower than UCase() /LCase()
Hello again said. You're right; of all the methods, the FindString() function is the slowest, with the CompareMemoryString() function being the fastest. Although string constants can be passed to procedures to be evaluated by the CompareMemoryString() function, the speed compromise is huge.

However, as you can see in this example, a simple re-assignment of the string constant to a regular string would solve this problem quite easily, without any loss of speed. And since comparisons against string constants should be known beforehand, such an approach shouldn't be much of an issue:

Code: Select all

s$ = "hello said!"
#s = "HELLO Said!"

Procedure StrComp(a.s, b.s)
  ProcedureReturn CompareMemoryString(@a, @b, #PB_String_NoCase)  
EndProcedure

a$ = #s : t = ElapsedMilliseconds()
For L = 1 To 1000000
  CompareMemoryString(@s$, @a$, #PB_String_NoCase)
Next
Debug "Constant re-assignment: " + 
      Str(ElapsedMilliseconds() - t) + " milliseconds"

t = ElapsedMilliseconds()
For L = 1 To 1000000
  StrComp(s$, #s)
Next
Debug "Procedure conversion: " +
      Str(ElapsedMilliseconds() - t) + " milliseconds"
A very good alternative until your wish is granted. :wink:

Re: an equal '=' test string not case sensitive

Posted: Sat Jul 27, 2013 7:15 pm
by davido
Hi TI-994A,

To give a fairer test, shouldn't the procedure call in the second example be eliminated, thus increasing the speed by a factor of 3 to 4?

Re: an equal '=' test string not case sensitive

Posted: Sat Jul 27, 2013 7:48 pm
by TI-994A
davido wrote:To give a fairer test, shouldn't the procedure call in the second example be eliminated, thus increasing the speed by a factor of 3 to 4?
Hello davido. You're right, excluding the procedure call would increase the speed, but that wouldn't be a fair evaluation as the function has to be called recursively.

Code: Select all

#s = "ABC"

Procedure StrComp(a.s, b.s)
  ProcedureReturn CompareMemoryString(@a, @b, #PB_String_NoCase)  
EndProcedure

a$ = #s
s$= "abc"
Debug CompareMemoryString(@s$, @a$, #PB_String_NoCase)
s$= "aBc"
Debug CompareMemoryString(@s$, @a$, #PB_String_NoCase)
s$= "abC"
Debug CompareMemoryString(@s$, @a$, #PB_String_NoCase)

s$= "abc"
Debug StrComp(s$, #s)
s$= "aBc"
Debug StrComp(s$, #s)
s$= "abC"
Debug StrComp(s$, #s)
The loops were used only for benchmarking, but in actual implementation the strings to be evaluated would change outside the procedure. :)