DelphiFAQ Home Search:

Compare two strings with wildcards (*, ?)

 

comments4 comments. Current rating: 4 stars (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]; { in Delphi 2/3: = string }
  NameStr = string[12];  { in Delphi 2/3: = string }
  ExtStr  = string[3];   { in Delphi 2/3: = string }

{$V-} { in Delphi 2/ 3 to switch off "strict var-strings" }

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
          { we need to synchronize }
          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 { automatically append .* }
    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:

2006-02-06, 05:56:20
anonymous from Poland  
rating
This function return wrong result for:

WildComp('*p', 'autop.bmp')

so it's not useful
2006-02-06, 08:50:04
anonymous from United States  
rating
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.
2007-03-19, 09:44:47
SpamMe92000@yahoo.com from United Kingdom  
rating
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
2007-03-19, 11:30:30
thomas_kelsey@techie.com from United Kingdom  
rating
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;

 

 

Email address (not necessary):

Rate as
Hide my email when showing my comment.
Please notify me once a day about new comments on this topic.
Please provide a valid email address if you select this option.
 
It seems that you are
from Washington, US .

Info/ Feedback on this

Show city and country
Show country only
Hide my location
Leave your comment here:
Please type in the code:
photo Add a picture:

Please do not post inappropriate pictures. Inappropriate pictures include pictures of minors and nudity. The owner of this web site reserves the right to delete such material.