Suche mit Wildcards
Vorbemerkung
Die Suche mit Wildcards (wildcard search) ist vor allem aus dem Dateisystem geläufig. '?' steht für ein einzelnes Zeichen, '*' für eine beliebige Zeichenkombination (oder kein Zeichen). Häufig werden hier Dateinamen gesucht z.B. T*.doc, das alle Dokumente mit T am Anfang findet.
Leider sucht man eine funktionierende Stringsuche nach diesen Regeln in Delphi vergeblich und auch die Sources, die ich so im Netz fand, hatten so ihre Macken.
Suche mit Wildcard |
Aufruf: | WPos(Wildcard,Text [,StartPos][,'*'][,'?']) |
Rückgabe: | tposition: .start, .len |
wpos() ist pos() mit Wildcards: ? für ein beliebiges Zeichen, * für 0-n beliebige Zeichen. Die Syntax orientiert sich am pos-Befehl, der einfachste Aufruf ist
wpos(wild,s).
Wpos findet das erste Auftreten des Suchstrings Wild. Da die Länge größer sein kann als die des Suchstrings muß auch die Länge der gefundenen Passage zurückgegeben werden. Daher wird das Ergebnis in einem TPosition-Record zurückgegeben. Den Start des gefundenen Strings erhält man z.B. mit wpos().start
Das Isolieren des gefundenen Strings kann mit folgender Sequenz erfolgen
with wpos('?x','Text') do
s := copy('Text',start,len);
Durch Angabe der Startposition eignet sich wpos auch zum Parsen. Für Sonderfälle können die Wildcards durch beliebige Zeichen ausgetauscht werden.
Hier nun der vollständige Code
Type
TPosition = record // Position eines Substrings in einem String
start,len: integer;
end;
{ -------------------------------------------------
Wildcard-Compare von Dr. Ecki
mit Rückgabe gefundene Position
-------------------------------------------------}
function WPos(const Wild,S: string; const StartPos: Integer = 1;
const all: char='*'; const one: char='?'): TPosition;
var lw,ls: integer;
cw: char;
//-- match ab einer bestimmten Position ps, Result wird als res übergeben,
Rückgabe gefunden: ja/nein --//
function match(ps: integer; var res: TPosition): boolean;
var i: integer;
begin
result := False;
res.start := ps; // Anfang schon mal merken
for i := 1 to lw do
begin
if ps>ls then // Falls Schleife noch läuft und String schon
// zuende, dann Fehler
exit;
cw := wild[i];
if cw = one then // Aktueller Wild-char
inc(ps) // ?: egal, nur hochzählen
else
if cw = all then
begin
if i=lw then // *: Wenn es das letzte Zeichen ist, dann muß
// man nichts tun!
ps := ls+1 // Dann bis zum Ende
else
begin
if wild[i+1]<>all then // Wenn danach noch ein * kommt, dann auch
nicht
begin
if wild[i+1]=one then
raise exception.Create('illegal *? in wpos');
ps := charpos(s,wild[i+1],ps); // sonst zum nächsten Zeichen
// springen
end;
end;
end
else // normales Zeichen im Wildstring
if cw<>s[ps] then
exit
else
inc(ps);
end;
res.len := ps-res.start;
result := True;
end;
// main
var ps: integer;
label nomatch;
begin
ls := length(s);
lw := length(wild);
//------ Abfangen diverser Sonderfälle ------
if (lw=0) or (ls=0) then
goto nomatch;
cw := wild[1];
if lw=1 then // nur ein Sonderzeichen abfangen
begin
if (cw=all) or ((cw=one) and (ls=1))then
begin
result.start:=1;
result.len := ls;
exit;
end;
if (cw=one) then
goto nomatch
end;
ps := StartPos; // nsp = NextSearchPosition
//------ Hauptschleife ------
repeat
cw := wild[1];
if cw=one then // Sonderfall erstes Suchzeichen ?
begin
if (wild[2]=all) or (wild[2]=one) then
raise exception.Create('illegal *? in wpos');
ps := charpos(s,wild[2],ps+1)-1;
end
else
if cw<> all then
ps := charpos(s,cw,ps); // nächstes Auftauchen von wild[1 suchen]
if ps=0 then // 0 = nicht gefunden
goto nomatch;
// ================= Aufruf von Match immer ab ps ====================
if match(ps,result) then // Wenn gefunden, dann abbrechen
exit; // -->
// ===================================================================
inc(ps);
until ps>=ls;
nomatch:
result.start := 0;
result.len := 0;
end;

|