近日在和朋友讨论 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;

|