飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 2114|回复: 0

两个不错的通配符比较函数

[复制链接]
  • TA的每日心情
    开心
    2019-9-19 16:05
  • 签到天数: 4 天

    [LV.2]偶尔看看I

    发表于 2007-2-8 09:52:21 | 显示全部楼层 |阅读模式
    近日在和朋友讨论 MaskMatch 时偶得2个不错的算法。
    函数1 只支持'*','?'模糊匹配。速度比采用递归算法的快近2倍,比TMask方法快很多。
    函数2 完全支持正规表达式。速度于之前的相同。(不会正规表达式的朋友慎用)


    // ===========================
    // Funtion 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;


    // ===========================
    // Funtion 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;


    [ 本帖最后由 Moodsky 于 2007-2-8 10:13 编辑 ]
    PYG19周年生日快乐!
    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表