Seite 1 von 1

String-Vergleich mit Wildcards

Verfasst: 18.08.2006 17:02
von NicTheQuick
Hi Leute!

Da gewünscht wurde, dass man bei meiner kleinen Datenbank beim Suchen
auch Wildcards benutzen kann, habe ich mich eben mal rangesetzt und etwas
zusammengeschustert, was nicht schön aussieht, aber funktioniert.

Ein paar Kommentare hätte ich mir wohl mal leisten sollen, aber naja.

Der optionale Suchmasken-Parameter ist für Suchen gedacht, die man immer
wieder mit der selben Suchmaske ausführen will.

///Edit 1:
Added: Nach Remis Idee ist der Code nun auch kompatibel mit UNICODE-Strings.

///Edit 2:
Changed: Jetzt wird das Array nicht mehr gebraucht. Somit ist die
Procedure jetzt speicherschonender und sogar minimal schneller.

Hier ist der Code:

Code: Alles auswählen

Procedure CompareWithWildcards(String.s, StringToFind.s = "")
  Static oldStringToFind.s, max.l
  Static NewList vPart.s()
  Protected *c.Character, p.s = "", a.l, fr.l = #False, *c2.Character, *tmp
 
  Macro Add(zstring)
    If AddElement(vPart()) : vPart() = zstring : max + 1 : EndIf
  EndMacro
 
  If StringToFind = ""
    If oldStringToFind = "" : ProcedureReturn #False : EndIf
    StringToFind = oldStringToFind
  Else
    oldStringToFind = StringToFind
    ClearList(vPart())
    *c = @StringToFind : a = 0 : max = 0
    While *c\c
      If *c\c = '*'
        If a
          If ((Not PeekC(*c - SizeOf(Character)) = '*') And fr) Or max = 0
            If max Or fr : Add(p) : EndIf
            Add("*") : p = ""
            fr = #False
          Else
            p = ""
          EndIf
        Else
          Add("*")
        EndIf
      ElseIf *c\c = '?'
        If fr Or a = 0 : p + Chr(*c\c) : EndIf
      Else
        p + Chr(*c\c)
        fr = #True
      EndIf
      *c + SizeOf(Character) : a + 1
    Wend
   
    If p <> "" : Add(p) : EndIf
    max - 1
  EndIf
 
  a = 0
  *c = @String
  FirstElement(vPart())
  Repeat
    If vPart() = "*"
      If a = max
        ProcedureReturn #True
      EndIf
      *tmp = *c
      NextElement(vPart())
      Repeat
        *c = *tmp
        *c2 = PeekL(@vPart()) ;anders als bei Arrays
        While *c2\c
          If *c\c = 0 : ProcedureReturn #False : EndIf
          If *c2\c <> *c\c And *c2\c <> '?' : Break : EndIf
          *c + SizeOf(Character) : *c2 + SizeOf(Character)
        Wend
        If *c2\c = 0 : Break : EndIf
        *tmp + SizeOf(Character)
      ForEver
      *c = *tmp
    Else
      *c2 = PeekL(@vPart()) ;anders als bei Arrays
      While *c2\c
        If *c\c = 0 : ProcedureReturn #False : EndIf
        If *c2\c <> *c\c And *c2\c <> '?' : ProcedureReturn #False : EndIf
        *c + SizeOf(Character) : *c2 + SizeOf(Character)
      Wend
      If a = max And *c\c : ProcedureReturn #False : EndIf
      NextElement(vPart())
    EndIf
    a + 1
  Until a = max + 1
 
  ProcedureReturn #True
EndProcedure

Debug CompareWithWildcards("May", "*May*")

Debug CompareWithWildcards("Mayer ist schlau", "M??er *schlau*")
Debug CompareWithWildcards("Meyer ist sehr schlauer", "")
Debug CompareWithWildcards("Meier ist ultra schlauer", "")
Debug CompareWithWildcards("Mayar ist ganz schön schlau", "")

text.s="2030501"
Suchmuster.s="??3"
Debug CompareWithWildcards(text, Suchmuster)

text.s="2030501"
Suchmuster.s="*5"
Debug CompareWithWildcards(text, Suchmuster)

text.s="2030501"
Suchmuster.s="*6?1"
Debug CompareWithWildcards(text, Suchmuster)

Verfasst: 18.08.2006 17:15
von remi_meier
Scheint zu funktionieren :allright:
Nur ein kleiner 'Bug': Benutze doch *c+Sizeof(CHARACTER) anstatt *c+1
um auch Unicode zu unterstützen :)

Verfasst: 24.08.2006 13:17
von NicTheQuick
DarkDragon hat mich gerade darauf hingewiesen, dass du was gepostet
hast. Das hab ich wohl irgendwie übersehen. /:->

Aber jetzt gibt es oben auch den UNICODE-kompatiblen Code. :allright:

Verfasst: 24.08.2006 17:47
von remi_meier
Super, danke!
Diese Prozedur wird mir sicher einmal die Arbeit erleichtern :allright:

Verfasst: 24.08.2006 20:32
von NicTheQuick
Demnächst wollte ich sie noch verbessern, damit man nicht ein Array und
eine LinkedList braucht, sondern nur noch die LinkedList. :)

Verfasst: 24.08.2006 23:39
von NicTheQuick
Somit wäre das auch erledigt. Das hatte ich schon so lange vor... (s. 1. Post)

Verfasst: 23.10.2006 18:47
von AND51
Bug:

Code: Alles auswählen

Debug CompareWithWildcards("May", "*May*") 
Funktioniert nicht...

Verfasst: 23.10.2006 19:31
von NicTheQuick
Aha, ein Übeltäter!

Habs korrigiert.

Das heißt also, dass * auch gar nichts sein kann?

Verfasst: 23.10.2006 19:41
von Kaeru Gaman
NicTheQuick hat geschrieben:Das heißt also, dass * auch gar nichts sein kann?
yup, sollte es zumindest.
wird nicht in allen interfaces unterstützt, ist aber die bedeutung.