Function to check a string with embedded wild cards

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
humble
New User
New User
Posts: 3
Joined: Thu May 29, 2014 5:36 pm

Function to check a string with embedded wild cards

Post by humble »

Microsoft VBA provides many ready function like the string matching, e.g. "A" is like "*A". The following procedures are not too long (glory to God) and they may ease your work. Enjoy :lol:.

Code: Select all

Procedure FindStringWithHoles(sRead.s, sPattern.s, pos=1, Mode=#PB_String_NoCase)
; This function will be called by StringIsLike()
; Created on May20,2014
    Protected c, cMax, MarkCount, Lastpos, posMatch, sCheckThis.s
    cMax = CountString(sPattern, Chr(63))+1     ; ? is Chr(63)
    For c=1 To cMax
        
        sCheckThis = StringField(sPattern,c,Chr(63))
        If sCheckThis=""
            pos + 1
            MarkCount + 1
            Continue
        EndIf
        
        posMatch = FindString(sRead, sCheckThis, pos, Mode)
        If posMatch=0
            Lastpos = 0     ; reset for next seek from C=1
            Break
        Else
            If c=1
                If Lastpos = 0 : Lastpos = posMatch : EndIf
                pos = posMatch + Len(sCheckThis) + 1   ; keep checking with next forward position
            Else
                If posMatch > pos  ; failed if matching is not from the first seeking position
                    c = 0   ; re-seek sPattern at last position
                    MarkCount = 0 : Lastpos = 0     ; reset for next seek from C=1
                    Continue
                Else    ; match at the first seeking position
                    If Lastpos = 0
                        Lastpos = posMatch - MarkCount
                    Else
                        If c = cMax : Break : EndIf     ; mission succeeded
                    EndIf
                    pos = posMatch + Len(sCheckThis) + 1   ; keep checking with next forward position
                    If pos>Len(sRead) : Break : EndIf
                EndIf
            EndIf
        EndIf
    Next c    
    ProcedureReturn Lastpos
EndProcedure


Procedure StringIsLike(sRead.s, sPattern.s, Mode=#PB_String_NoCase)
; Test two strings whether they match
; sPattern allows wild card character only like * Chr(42)
; Created on May20,2014
    Protected c, cMax, pos, posMatch, IsLike=1, sCheckThis.s
    
    cMax = CountString(sPattern, Chr(42))+1
    For c=1 To cMax
        sCheckThis = StringField(sPattern,c,Chr(42))
        If sCheckThis="" : Continue : EndIf
        
        posMatch = FindStringWithHoles(sRead, sCheckThis, pos, Mode)
        If posMatch=0
            IsLike = 0
            Break
        Else
            If c=cMax   ; last check unit
                If Len(sRead)-posMatch+1<> Len(sCheckThis)
                    IsLike = 0
                    Break
                EndIf
            Else
                pos = posMatch + Len(sCheckThis)    ; new position to start seeking
            EndIf
        EndIf
    Next c
    ProcedureReturn IsLike
EndProcedure

Debug FindStringWithHoles("This is likle a cake", "?a", 15)	; 17
Debug StringIsLike("This is lik1e a cake", "T?is is*")  ; 1
Debug StringIsLike("This is lik1e a cake", "*is *is*")  ; 1
User avatar
Tenaja
Addict
Addict
Posts: 1959
Joined: Tue Nov 09, 2010 10:15 pm

Re: Function to check a string with embedded wild cards

Post by Tenaja »

We already have this...read up on the Regular Expression library.
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: Function to check a string with embedded wild cards

Post by PB »

For Windows only, this...

Code: Select all

Debug StringIsLike("This is lik1e a cake", "T?is is*")  ; 1
Debug StringIsLike("This is lik1e a cake", "*is *is*")  ; 1
...is just the same as this:

Code: Select all

Debug PathMatchSpec_("This is lik1e a cake", "T?is is*")  ; 1
Debug PathMatchSpec_("This is lik1e a cake", "*is *is*")  ; 1
And no procedure needed. Unless I'm missing something?
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
User avatar
Tenaja
Addict
Addict
Posts: 1959
Joined: Tue Nov 09, 2010 10:15 pm

Re: Function to check a string with embedded wild cards

Post by Tenaja »

Should be cross platform, since it only uses PB commands:

Code: Select all

; Uses these RegEx characters.
; . 	Any character except new line (\n)
; ^	Start of a string.
; $ 	End of string, or end of line in multi-line pattern
; * 	0 or more
; ? 	0 or 1
; \ 	Escape following character (requires duplicating for a filepath)

Procedure.i PathMatchSpec(path.s, spec.s)
	
	; replace dos "*" wildcards with regex "." wildcard, 0 or more
	spec = ReplaceString(spec, "*", ".*")
	; replace dos backslash with an escaped backslash. Mark Start of String, and Terminate with End of String.
	spec = "^" + ReplaceString(spec, "\", "\\") + "$"
	
	If Not CreateRegularExpression(0, spec)
		ProcedureReturn -1
	EndIf
	
	ProcedureReturn MatchRegularExpression(0, path)
EndProcedure


; Test:
CompilerIf  #PB_Compiler_IsMainFile    
	s.s = ""
	
	s = "Hello.txt"
	Debug PathMatchSpec(s, "*.txt")		; 1
	
	s = "Hello there .txt.txts"
	Debug PathMatchSpec(s, "*.txt")		;0
	
	s =  "c:\windows\test.txt"
	Debug PathMatchSpec(s, "c:\windows\*")		; 1
	
	s =  "c:\windows\test" + #CR$ + ".txt"
	Debug PathMatchSpec(s, "*.txt")		; 1
CompilerEndIf 
... like I said, get familiar with the RegEx library. There are probably other OS versions of PathMatchSpec, but I try to avoid API.

Edited to add a "start of String"
Last edited by Tenaja on Sun Jun 01, 2014 12:23 am, edited 1 time in total.
User avatar
Tenaja
Addict
Addict
Posts: 1959
Joined: Tue Nov 09, 2010 10:15 pm

Re: Function to check a string with embedded wild cards

Post by Tenaja »

Also, for the OP, search is your friend:
http://purebasic.fr/english/search.php? ... s=wildcard
humble
New User
New User
Posts: 3
Joined: Thu May 29, 2014 5:36 pm

Re: Function to check a string with embedded wild cards

Post by humble »

Tenaja wrote:Should be cross platform, since it only uses PB commands:

Code: Select all

; Uses these RegEx characters.
; . 	Any character except new line (\n)
; $ 	End of string, or end of line in multi-line pattern
; * 	0 or more
; ? 	0 or 1
; \ 	Escape following character (requires duplicating for a filepath)

Procedure.i PathMatchSpec(path.s, spec.s)
	
	; replace dos "*" wildcards with regex "." wildcard, 0 or more
	spec = ReplaceString(spec, "*", ".*")
	; replace dos backslash with an escaped backslash. Terminate with End of String.
	spec = ReplaceString(spec, "\", "\\") + "$"
	
	If Not CreateRegularExpression(0, spec)
		ProcedureReturn -1
	EndIf
	
	ProcedureReturn MatchRegularExpression(0, path)
EndProcedure


; Test:
CompilerIf  #PB_Compiler_IsMainFile    
	s.s = ""
	
	s = "Hello.txt"
	Debug PathMatchSpec(s, "*.txt")		; 1
	
	s = "Hello there .txt.txts"
	Debug PathMatchSpec(s, "*.txt")		;0
	
	s =  "c:\windows\test.txt"
	Debug PathMatchSpec(s, "c:\windows\*")		; 1
	
	s =  "c:\windows\test" + #CR$ + ".txt"
	Debug PathMatchSpec(s, "*.txt")		; 1
CompilerEndIf 
... like I said, get familiar with the RegEx library. There are probably other OS versions of PathMatchSpec, but I try to avoid API.
I like cross platform codes because I am attempting to move out from Windows (17GB) to Linux (1GB). I overlooked the existing library RegEx since it names itself not explicit to handling string like 'String' library where I first attempted to find function like StringIsLike().

With PathMatchSpec(), surprised results I got:
s = "Hello.txt"
Debug PathMatchSpec(s, "xt") ; 1

s = "Hello there .txt.txts"
Debug PathMatchSpec(s, "s") ; 1

s = "c:\windows\test.txt"
Debug PathMatchSpec(s, "c:\*\?.txt") ; 1

s = "c:\windows\test" + #CR$ + ".txt"
Debug PathMatchSpec(s, "*t#CR$.txt") ; 0
User avatar
Tenaja
Addict
Addict
Posts: 1959
Joined: Tue Nov 09, 2010 10:15 pm

Re: Function to check a string with embedded wild cards

Post by Tenaja »

Oops, clearly it needs a little more work.

Replace this...

Code: Select all

spec = ReplaceString(spec, "\", "\\") + "$"
with this...

Code: Select all

spec = "^" + ReplaceString(spec, "\", "\\") + "$"
It now seems to work with each of the samples, although I have not tested it thoroughly.
BarryG
Addict
Addict
Posts: 4126
Joined: Thu Apr 18, 2019 8:17 am

Re: Function to check a string with embedded wild cards

Post by BarryG »

How can I make this case-sensitive with the matches? Like this:

Code: Select all

Procedure.i PathMatchSpec(path.s,spec.s)
  spec=ReplaceString(spec,"*",".*")
  spec=ReplaceString(spec,"\","\\")+"$"
  If Not CreateRegularExpression(0,spec)
    ProcedureReturn -1
  EndIf
  ProcedureReturn MatchRegularExpression(0,path)
EndProcedure

Debug PathMatchSpec("Twunk_16.exe","t?unk*") ; 1, but want 0
Debug PathMatchSpec("Twunk_16.exe","T?unk*") ; 1
BTW Tenaja: If I use your fix above, then both matches return 0, which I think is wrong:

Code: Select all

Procedure.i PathMatchSpec(path.s,spec.s)
  spec=ReplaceString(spec,"*",".*")
  spec="^"+ReplaceString(spec,"\","\\")+ "$"
  If Not CreateRegularExpression(0,spec)
    ProcedureReturn -1
  EndIf
  ProcedureReturn MatchRegularExpression(0,path)
EndProcedure

Debug PathMatchSpec("Twunk_16.exe","t?unk*") ; 0
Debug PathMatchSpec("Twunk_16.exe","T?unk*") ; 0
Little John
Addict
Addict
Posts: 4777
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Function to check a string with embedded wild cards

Post by Little John »

BarryG wrote: Wed May 01, 2024 1:06 pm How can I make this case-sensitive with the matches? Like this:

Code: Select all

Procedure.i PathMatchSpec(path.s,spec.s)
  spec=ReplaceString(spec,"*",".*")
  spec=ReplaceString(spec,"\","\\")+"$"
  If Not CreateRegularExpression(0,spec)
    ProcedureReturn -1
  EndIf
  ProcedureReturn MatchRegularExpression(0,path)
EndProcedure

Debug PathMatchSpec("Twunk_16.exe","t?unk*") ; 1, but want 0
Debug PathMatchSpec("Twunk_16.exe","T?unk*") ; 1
It should be case-sensitive by default.
It should be case insensitive, only when CreateRegularExpression(0, spec, #PB_RegularExpression_NoCase) is used.
With which PB version did you encounter this problem?
Post Reply