站内搜索

Delphi学习:2个不错的通配符比较函数

近日在和朋友讨论 MaskMatch 时偶得2个不错的算法。
   函数1 只支持'*','?'模糊匹配。速度比采用递归算法的快近2倍,比TMask方法快很多。
   函数2 完全支持正规表达式。速度于之前的相同。(不会正规表达式的朋友慎用)


  // ===========================
   // Function 1
   // ===========================

  // Check if the string can match the wildcard. It can be used for unicode strings as well!
   // C: 2004-07-24 | M: 2004-07-24
   function MaskMatch(const aPattern, aSource: string): Boolean;
   var
   StringPtr, PatternPtr: PChar;
   StringRes, PatternRes: PChar;
   begin
   Result := False;
   StringPtr := PChar(UpperCase(aSource));
   PatternPtr := PChar(UpperCase(aPattern));
   StringRes := nil;
   PatternRes := nil;
   repeat
   repeat // ohne vorangegangenes "*"
   case PatternPtr^ of
   #0 : begin
   Result := StringPtr^ = #0;
   if Result or (StringRes = nil) or (PatternRes = nil) then Exit;
   StringPtr := StringRes;
   PatternPtr := PatternRes;
   Break;
   end;
   '*': begin
   Inc(PatternPtr);
   PatternRes := PatternPtr;
   Break;
   end;
   '?': begin
   if StringPtr^ = #0 then Exit;
   Inc(StringPtr);
   Inc(PatternPtr);
   end;
   else begin
   if StringPtr^ = #0 then Exit;
   if StringPtr^ <> PatternPtr^ then
   begin
   if (StringRes = nil) or (PatternRes = nil) then Exit;
   StringPtr := StringRes;
   PatternPtr := PatternRes;


  Break;
   end else
   begin
   Inc(StringPtr);
   Inc(PatternPtr);
   end;
   end;
   end;
   until False;

  repeat // mit vorangegangenem "*"
   case PatternPtr^ of
   #0 : begin
   Result := True;
   Exit;
   end;
   '*': begin
   Inc(PatternPtr);
   PatternRes := PatternPtr;
   end;
   '?': begin
   if StringPtr^ = #0 then Exit;
   Inc(StringPtr);
   Inc(PatternPtr);
   end;
   else begin
   repeat
   if StringPtr^ = #0 then Exit;
   if StringPtr^ = PatternPtr^ then Break;
   Inc(StringPtr);
   until False;
   Inc(StringPtr);
   StringRes := StringPtr;
   Inc(PatternPtr);
   Break;
   end;
   end;
   until False;
   until False;
   end;


  // ===========================
   // Function 2
   // ===========================

  function _MatchPattern(aPattern, aSource: PChar): Boolean;
   begin
   Result := True;
   while (True) do
   begin
   case aPattern[0] of
   #0 : begin
   //End of pattern reached.
   Result := (aSource[0] = #0); //TRUE if end of aSource.
   Exit;
   end;

  '*': begin //Match zero or more occurances of any char.
   if (aPattern[1] = #0) then
   begin
   //Match any number of trailing chars.
   Result := True;
   Exit;
   end else
   Inc(aPattern);

  while (aSource[0] <> #0) do
   begin
   //Try to match any substring of aSource.
   if (_MatchPattern(aSource, aPattern)) then
   begin
   Result := True;
   Exit;
   end;

  //Continue testing next char...
   Inc(aSource);
   end;
   end;

  '?': begin //Match any one char.
   if (aSource[0] = #0) then
   begin
   Result := False;
   Exit;
   end;


  //Continue testing next char...
   Inc(aSource);
   Inc(aPattern);
   end;

  '[': begin //Match given set of chars.
   if (aPattern[1] in [#0,'[',']']) then
   begin
   //Invalid Set - So no match.
   Result := False;
   Exit;
   end;

  if (aPattern[1] = '^') then
   begin
   //Match for exclusion of given set...
   Inc(aPattern, 2);
   Result := True;
   while (aPattern[0] <> ']') do
   begin
   if (aPattern[1] = '-') then
   begin
   //Match char exclusion range.
   if (aSource[0] >= aPattern[0]) and (aSource[0] <= aPattern[2]) then
   begin
   //Given char failed set exclusion range.
   Result := False;
   Break;
   end else
   Inc(aPattern, 3);
   end else
   begin
   //Match individual char exclusion.
   if (aSource[0] = aPattern[0]) then
   begin
   //Given char failed set element exclusion.
   Result := False;
   Break;
   end else


  Inc(aPattern);
   end;
   end;
   end else
   begin
   //Match for inclusion of given set...
   Inc(aPattern);
   Result := False;
   while (aPattern[0] <> ']') do
   begin
   if (aPattern[1] = '-') then
   begin
   //Match char inclusion range.
   if (aSource[0] >= aPattern[0]) and (aSource[0] <= aPattern[2]) then
   begin
   //Given char matched set range inclusion.
   // Continue testing...
   Result := True;
   Break;
   end else
   Inc(aPattern, 3);
   end else
   begin
   //Match individual char inclusion.
   if (aSource[0] = aPattern[0]) then
   begin
   //Given char matched set element inclusion.
   // Continue testing...
   Result := True;
   Break;
   end else
   Inc(aPattern);
   end;
   end;
   end;

  if (Result) then
   begin
   //Match was found. Continue further.
   Inc(aSource);
   //Position Pattern to char after "]"


  while (aPattern[0] <> ']') and (aPattern[0] <> #0) do Inc(aPattern);
   if (aPattern[0] = #0) then
   begin
   //Invalid Pattern - missing "]"
   Result := False;
   Exit;
   end else
   Inc(aPattern);
   end else
   Exit;
   end;

  else begin //Match given single char.
   if (aSource[0] <> aPattern[0]) then
   begin
   Result := False;
   Break;
   end;

  //Continue testing next char...
   Inc(aSource);
   Inc(aPattern);
   end;
   end;
   end;
   end;

  function MatchPattern(const aPattern, aSource: string): Boolean;
   begin
   Result := _MatchPattern(PChar(aPattern), PChar(aSource));
   end;

  • 上一篇:Delphi学习:查句柄知多少
  • 下一篇:Delphi初学者参考(二)