Delphi-PRAXiS
Seite 4 von 5   « Erste     234 5      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Neuen Beitrag zur Code-Library hinzufügen (https://www.delphipraxis.net/33-neuen-beitrag-zur-code-library-hinzufuegen/)
-   -   Delphi Stringvergleich mit Wildcards (https://www.delphipraxis.net/125813-stringvergleich-mit-wildcards.html)

himitsu 22. Jun 2009 15:39

Re: Stringvergleich mit Wildcards
 
menno ... ich schau mal

eigentlich dachte ich, diesbezüglich hätt ich nichts verändert :oops:

hatte grad nur noch einen Parameter nachgetragen, damit bei den "wiederholenden" Aufrufen die äußeren und eventuell recht großen Strings nicht mit im Result landen (führendes und letztes * in der Abfrage).
(siehe nächster Beitrag)

ich glaub ich bau so'nen Assert mal mit in die Unit direkt ein ... so auch für die Zukunft :nerd:

himitsu 22. Jun 2009 18:20

Re: Stringvergleich mit Wildcards
 
das ist eigentlich zu peinlich zum Erwähnen: :oops:
meine Tests hatte ich, da es einfacher zum Debuggen war, meißt direkt mir der Hauptgrundfunktion gemacht und da traten einige Fehler nicht auf ...
z.B. wie der 1-Startindex bei String, welcher nicht als 0-Index für PChar angegeben wurde
und ein Copy&Paste-Fehler, wo Result gleich mit True initialisiert wurde, anstatt mit False :wall:

nja, hatte jetzt dabei auch gleich noch eine Idee bekommen, wie der Vergleich vorzeitig abbrechen kann, wenn das letzte Maskenzeichen ein * ist ... bislang wurde dennoch der restliche Stringinhalt geprüft.

und wie schon erwähnt, funktioniert nun auch sowas: suchen folgender Masken in einem String:
wenn Maskenanfang und -ende * lauten, dann wird das dazwischen gesucht und zusammen mit dem neuen cfIgnoreOuterAsterix kann man so auch "recht" speichersparend den einen String nach allen Vorkommen der "Teil"Maske (ohne erstes und letztes * ) durchforsten :-D
Delphi-Quellcode:
Var S, Sr: String;
  i, i2: Integer;
  X: TStringDynArray;

Begin
  S := 'i|F1|V1|F2|i'
    + 'i|F1|V2|F2|i'
    + 'i|F1|V3|F2|i';

  i := 1;
  i2 := -1;
  While True do Begin
    X := MatchStringEx('*F1*F2*', S, [], i, i);
    If X = nil Then Break;
    Sr := X[1];
    Inc(i2);

    ShowMessage('1:'#13#10'Sr[' + IntToStr(i2) + '] = "' + Sr + '"');
  End;



  i := 1;
  i2 := -1;
  While True do Begin
    X := MatchStringEx('*F1*F2*', S, [cfIgnoreOuterAsterix], i, i);
    If X = nil Then Break;
    Sr := X[0];
    Inc(i2);

    ShowMessage('2:'#13#10'Sr[' + IntToStr(i2) + '] = "' + Sr + '"');
  End;



  i := MatchStringCount('*F1*F2*', S, []);

  ShowMessage('3:'#13#10'C = ' + IntToStr(i));



  X := MatchStringAll('*F1*F2*~a~a~a', S, []);
  If X <> nil Then Begin
    Sr := '';
    For i := 0 to Length(X) div 3 - 1 do
      Sr := Sr + 'Sr[' + IntToStr(i) + '] = "' + X[i * 3 + 1] + '"'#13#10
  End Else Sr := 'nichts gefunden';

  ShowMessage('4:'#13#10 + Sr);



  X := MatchStringAll('*V{13}*', S, []);
  If X <> nil Then Begin
    Sr := '';
    For i := 0 to Length(X) div 3 - 1 do
      Sr := Sr + 'Sr[' + IntToStr(i) + '] = "' + X[i * 3 + 1] + '"'#13#10
  End Else Sr := 'nichts gefunden';

  ShowMessage('5:'#13#10 + Sr);


  X := MatchStringAll('*V{13}*', S, [cfIgnoreOuterAsterix]);
  If X <> nil Then Begin
    Sr := '';
    For i := 0 to High(X) do
      Sr := Sr + 'Sr[' + IntToStr(i) + '] = "' + X[i] + '"'#13#10
  End Else Sr := 'nichts gefunden';

  ShowMessage('6:'#13#10 + Sr);
theoretisch müßte auch sowas möglich sein (hab's jetzt nicht geteste)
Delphi-Quellcode:
X := MatchStringAll('*<img *src="*"*', S, [cfNotCaseSensitive, cfIgnoreOuterAsterix]);
da müßten nun abwechseln (evt. vorhandene) weitere Parameter und die URL in X drinstehn ... denk ich mal :gruebel:

Download siehe #26

GPRSNerd 22. Jun 2009 20:30

Re: Stringvergleich mit Wildcards
 
Hi,

besser, aber immer noch nicht auf dem guten Stand vor deinen Änderungen!

Folgende Tests schlagen immer noch fehl, größtenteils im zusammenhang mit Escaping:

Delphi-Quellcode:
Assert(MatchText('te\*23', 'te023')=false);
Assert(MatchText('te\?23', 'te023')=false);
Assert(MatchText('te\|23', 'te023')=false);
Assert(MatchText('te\\23', 'te023')=false);

Assert(MatchText('a*d|a*', 'abcdef')=True);
Du näherst dich wieder dem Ziel...

himitsu 22. Jun 2009 21:16

Re: Stringvergleich mit Wildcards
 
Bezüglich des Escaping:
Delphi-Quellcode:
'\': If not (cfOnlyWild in Flags) and (Mp + 1 < Me2) Then
       Case (Mp + 1)^ of '*', '?', '{', '~', '|', '\': Inc(Mp); End
     Else GoTo LElse;
kleiner Unterschied, große Wirkung :freak:
Delphi-Quellcode:
'\': Begin
       If not (cfOnlyWild in Flags) and (Mp + 1 < Me2) Then
         Case (Mp + 1)^ of '*', '?', '{', '~', '|', '\': Inc(Mp); End;
       GoTo LElse;
     End;
und das Andere ... eine kleine Variable übersehn
(neues MaskenEnde Me in '|' nicht gesetzt)


Download siehe #26

GPRSNerd 22. Jun 2009 22:12

Re: Stringvergleich mit Wildcards
 
Jau, jetzt geht wieder alles. :thumb:
Da sieht man wie wichtig Unittests sind bei so komplexen Funktionen! (benutze ich aber auch noch nicht so lange :angel2: ).

Danke für deinen Code (und deine Geduld mit meinen Nörgeleien :wink: )!

himitsu 23. Jun 2009 15:24

Re: Stringvergleich mit Wildcards
 
Liste der Anhänge anzeigen (Anzahl: 3)
Achtung: diese Veränderung bewirkt nur eine Verbesserung bei UnicodeStrings (PWideChar, WideString und UnicodeString)

Eigentlich hatte ich sowas zwar nicht vor, aber ich hab mich doch mal entschlossen die Unicodebehandlung aus meinem himXML zu extrahieren und hier mit einzubauen.

Es wird beim Unit-Start ein kleines Abbild des gesamten Unicode-2-Zeichensatzes angelegt und dann direkt darüber verglichen.

Nun wird also keine "LowerCase"-Kopie des Strings mehr benötigt, wenn nicht CaseSensitiv verglichen wird.
Und auch nicht mehr, wenn ein | im Suchmuster vorkommt.

Es gibt also vorallem bei langen Strings Vorteile, da nichts mehr rumkopiert werden muß. :stupid:

Alleine nachfolgender Code ist damit gleich so etwa 3 mal schneller, als mit der alten Version:

Allerdings ist diese Version nicht zur Geschwindigkeitsoptimierung gedacht,
(im Durchschnitt mag sich dieses nur minimal ändern und vorallam nicht bei CaseSensitivem Vergleich)
sondern der Speicheroptimierung (kein unnötiges Rumhantieren im Speichermanager)

Außerdem gibt es noch ein paar zusätzliche Funktionen
* WideLowerCase > sollte klar sein
* WideSameText > das auch
* und eine abgewandelte Version von Hagen's ELF-Hash, welcher auf Unicode erweitert wurde und auch noch die Maskenzeichen beachtet

Delphi-Quellcode:
Var T: LongWord;

T := GetTickCount;
For i := 1 to 100000 do Begin
  MatchText('',       'abcdef');
  MatchText('abc',    '');
  MatchText('abcdef', 'abcdef');
  MatchText('df',     'abcdef');
  MatchText('abc',    'abcdef');
  MatchText('def',    'abcdef');
  MatchText('abc?f',  'abcdef');
  MatchText('abc??f', 'abcdef');
  MatchText('abc*f',  'abcdef');
  MatchText('a?def',  'abcdef');
  MatchText('a??def', 'abcdef');
  MatchText('a*def',  'abcdef');
  MatchText('abcd?',  'abcdef');
  MatchText('abcd??', 'abcdef');
  MatchText('abcd???', 'abcdef');
  MatchText('abcd*',  'abcdef');
  MatchText('a?def',  'abcdef');
  MatchText('a??def', 'abcdef');
  MatchText('a*def',  'abcdef');
  MatchText('?cdef',  'abcdef');
  MatchText('??cdef', 'abcdef');
  MatchText('*cdef',  'abcdef');
  MatchText('b*c*f',  'abcdef');
  MatchText('a*c*f',  'abcdef');
  MatchText('a?c*f',  'abcdef');
  MatchText('a?d*f',  'abcdef');
  MatchText('*a*f*',  'abcdef');
  MatchText('*a?bf*', 'abcdef');
  MatchText('*c*f*',  'abcdef');
  MatchText('*c*d*',  'abcdef');
  MatchText('*c?f*',  'abcdef');
  MatchText('*d?f*',  'abcdef');
  MatchText('*',      '');
  MatchText('*',      'abcdef');
  MatchText('a*',     'abcdef');
  MatchText('*f',     'abcdef');

  MatchText('ab\*ef', 'abcdef');
  MatchText('ab\*ef', 'ab*ef');
  MatchText('ab\*ef', 'abcef');

  MatchText('a*d|a*', 'abcdef');
  MatchText('a*d|a*', 'abcdef');
  MatchText('a*d|z*', 'abcdef');
End;
T := GetTickCount - T;
ShowMessage(IntToStr(T));
und wo ich den Code einzeln hab, kann ich nun auch mal in Ruhe (einfacher) schauen, ob mit der LowerCase-Behandlung auch alles richtig läuft ... mal sehn ob auch alles wirklich stimmt :angel:

GPRSNerd 23. Jun 2009 19:54

Re: Stringvergleich mit Wildcards
 
Funktioniert noch alles ;-)

Ich werde in den nächsten Tagen mal ein paar Unittests für die unterschiedlichen String-Varianten, insbesondere Unicode, bauen und die Ergebnisse posten.

Cheers!

himitsu 26. Jul 2009 09:51

Re: Stringvergleich mit Wildcards
 
gibt jetzt keine großartigen Veränderungen ... ich hab nur den UTF8String hinzugefügt.

theoretisch/praktisch wird dort genauso verglichen, wie beim AnsiString, aber der Compiler nörgelt etwas rum, wenn man einen UTF8String an einen AnsiString übergeben möchte.
Drum hab ich einfach die Versionen mit AnsiString geklont und auf UTF8String (siehe System.pas) umgestellt. :angel:

[edit 11.02.2010]
Anhang entfernt > aktuelle Version siehe Beitrag #36

himitsu 1. Nov 2009 10:10

Re: Stringvergleich mit Wildcards
 
Und noch 'ne kleine Anpassung bezüglich "älteren" Delphis.

Mein D7 mochte verständlicher Weise das {$STRINGCHECKS OFF} nicht, welches Letztens mir reinrutschte.
Darum würde dieses etwas verschoben, bzw. von Delphi < 2009 versteckt.

[edit 11.02.2010]
Anhang entfernt > aktuelle Version siehe Beitrag #36

DelphiBandit 11. Feb 2010 10:35

Re: Stringvergleich mit Wildcards
 
Zitat:

Zitat von himitsu
gibt jetzt keine großartigen Veränderungen ... ich hab nur den UTF8String hinzugefügt.

ich habe gerade mal versucht die letzte Version der Unit einzubauen und zu benutzen. Leider werde ich mit Fehlermeldungen "MatchStringEx" "Doppeldeutig überladene Version von..." zugebomt (RS 2007, also ohne UniCode). Nehme ich die Version 1.2 ohne UTF8 lässt es sich durchkompilieren.

Gibt es dafür einen Compilerschalter, damit er auch die UTF8-Version durchkompilieren kann? Oder hat einer von Euch eine andere Idee warum das nicht funktioniert?


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:57 Uhr.
Seite 4 von 5   « Erste     234 5      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz