Delphi .NET (2) Database (72) Delphi IDE (90) Network (39) Printing (3) Strings (12) VCL (83) Windows with Delphi (243)
Exchange Links About this site Links to us
|
Compare two strings with wildcards (*, ?)
4 comments. Current rating: (4 votes). Leave comments and/ or rate it.
If you need to compare two strings where one contains wildcards (just * and ?), you may find the following useful - I used it years ago in a Turbo Pascal project.
It was a DOS program.. that's why it contains those type definitions at the top.
In Delphi 2/3 you may replace them just with string - otherwise you'll need to set the compiler syntax option "Strict Var-Strings" OFF = {$V-}.
The part at the bottom shows how to use the routine WildComp.
 | |  | | type
PathStr = string[128];
NameStr = string[12];
ExtStr = string[3];
function WildComp(FileWild,FileIs: PathStr): boolean;
var
NameW,NameI: NameStr;
ExtW,ExtI: ExtStr;
c: byte;
function WComp(var WildS,IstS: NameStr): boolean;
var
i, j, l, p : Byte;
begin
i := 1;
j := 1;
while (i<=length(WildS)) do
begin
if WildS[i]='*' then
begin
if i = length(WildS) then
begin
WComp := true;
exit
end
else
begin
l := i+1;
while (l < length(WildS)) and (WildS[l+1] <> '*') do
inc (l);
p := pos (copy (WildS, i+1, l-i), IstS);
if p > 0 then
begin
j := p-1;
end
else
begin
WComp := false;
exit;
end;
end;
end
else
if (WildS[i]<>'?') and ((length(IstS) < i)
or (WildS[i]<>IstS[j])) then
begin
WComp := false;
exit
end;
inc (i);
inc (j);
end;
WComp := (j > length(IstS));
end;
begin
c:=pos('.',FileWild);
if c=0 then
begin
NameW := FileWild;
ExtW := '*';
end
else
begin
NameW := copy(FileWild,1,c-1);
ExtW := copy(FileWild,c+1,255);
end;
c:=pos('.',FileIs);
if c=0 then
c:=length(FileIs)+1;
NameI := copy(FileIs,1,c-1);
ExtI := copy(FileIs,c+1,255);
WildComp := WComp(NameW,NameI) and WComp(ExtW,ExtI);
end;
begin
if WildComp('a*.bmp', 'auto.bmp') then ShowMessage('OK 1');
if not WildComp('a*x.bmp', 'auto.bmp') then ShowMessage('OK 2');
if WildComp('a*o.bmp', 'auto.bmp') then ShowMessage('OK 3');
if not WildComp('a*tu.bmp','auto.bmp') then ShowMessage('OK 4');
end.
| |  | |  |
Comments:
|
|
|
|
This function return wrong result for:
WildComp('*p', 'autop.bmp')
so it's not useful
|
|
|
|
|
The function was written in DOS days, and at that time
'*p' and 'autop.bmp' would not be matched by the operating system either.
You would have to use '*.*p' to match that file name.
|
|
|
|
|
there are 3 bugs:
* it returns false if filter string has a double * (unless the string to match has a '*' in as well) e.g. WildComp('a**o.b*p', 'auto.bmp') returns false instead of true
* '*' matches a '.' in the string to match: e.g.: WildComp('auto.*', 'auto.bmp.foo') returns true instead of false
* '*' matches only the first possible match, so WildComp('*ut.bmp', 'autout.bmp') returns false instead of true
|
|
|
|
|
This function works better:
unit comparewild;
{Copyright (C) 2007 Thomas Kelsey
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.}
// KNOWN BUGS: accepts wildcards in target string
interface
function WildComp(const mask: String; const target: String): Boolean;
function Test: Boolean;
implementation
function WildComp(const mask: String; const target: String): Boolean;
// '*' matches greedy & ungreedy
// simple recursive descent parser - not fast but easy to understand
function WComp(const maskI: Integer; const targetI: Integer): Boolean;
begin
if maskI > Length(mask) then begin
Result := targetI = Length(target) + 1;
Exit;
end;
if targetI > Length(target) then begin
// unread chars in filter or would have read '#0'
Result := False;
Exit;
end;
case mask[maskI] of
'*':
// '*' doesnt match '.'
if target[targetI] <> '.' then
// try with and without ending match - but always matches at least one char
Result := WComp(succ(maskI), Succ(targetI)) or WComp(maskI, Succ(targetI))
else
Result := False;
'?':
// ? doesnt match '.'
if target[targetI] <> '.' then
Result := WComp(succ(maskI), Succ(targetI))
else
Result := False;
else // includes '.' which only matches itself
if mask[maskI] = target[targetI] then
Result := WComp(succ(maskI), Succ(targetI))
else
Result := False;
end;// case
end;
begin
WildComp := WComp(1, 1);
end;
function Test: Boolean;
begin
Result := WildComp('a*.bmp', 'auto.bmp');
Result := Result and (not WildComp('a*x.bmp', 'auto.bmp'));
Result := Result and WildComp('a*o.bmp', 'auto.bmp');
Result := Result and (not WildComp('a*tu.bmp', 'auto.bmp'));
Result := Result and WildComp('a*o.b*p', 'auto.bmp') and (WildComp('a*to.*', 'auto.bmp'));
Result := Result and WildComp('a**o.b*p', 'auto.bmp');
Result := Result and (WildComp('*ut*.**', 'auto.bmp'));
Result := Result and (WildComp('*ut*.*.*', 'auto.bmp.splack'));
Result := Result and WildComp('**.**', 'auto.bmp') and (not WildComp('*ut*', 'auto.bmp'));
// '*' = at least 1 char
Result := Result and not WildComp('**', 'a');
// shows '.' <> '*'
Result := Result and (not WildComp('*ut*.*', 'auto.bmp.foo'));
// shows un-greedy match
Result := Result and (WildComp('*ut', 'autout'));
Result := Result and (not WildComp('auto?', 'auto'));
Result := Result and not WildComp('?uto', 'uto');
Result := Result and WildComp('aut?', 'auto');
Result := Result and WildComp('???', 'uto');
Result := Result and not WildComp('????', 'uto');
Result := Result and not WildComp('??', 'uto');
end;
|
|