Delphi 內建 MatchesMask (在 Masks 單元) 支援 * (多字元) 與 ? (單字元) 通配符比對。但早期版本或特定效能需求下,開發者可能需要自行實作。本文介紹一個自訂函數 IsABClikeAX,支援大小寫敏感/不敏感、中文、效能優化。
MatchesMask 快。* 與 ? 所有組合情況。IsLike (大小寫敏感) 與 WideCard (不敏感) 兩個介面函數。uses Math; // 需要 Min 函數
function IsABClikeAX(const ABC, AX: WideString): Boolean;
var
ABCStart, AXStart, ABCLen, AXLen: Integer;
EndPartABC, EndPartAX, SubAX: WideString;
Temp, ABCWWW, AXWWW: Integer;
begin
Result := True;
Temp := 0;
ABCStart := 1; AXStart := 1;
AXWWW := 1; ABCWWW := 1;
ABCLen := Length(ABC); AXLen := Length(AX);
while AXStart <= AXLen do
begin
if ABCStart > ABCLen then
begin
// 來源字串已盡,模式剩餘只能是結尾 *
Result := (AXStart = AXLen) and (AX[AXLen] = '*');
Break;
end;
case AX[AXStart] of
'?': begin Inc(AXStart); Inc(ABCStart); Continue; end;
'*': begin Inc(AXStart); Temp := 1; AXWWW := AXStart; ABCWWW := ABCStart; Continue; end;
else
// 取得下一個通配符前的定長子字串
EndPartAX := Copy(AX, AXStart, AXLen - AXStart + 1) + '?*';
SubAX := Copy(EndPartAX, 1, Min(Pos('?', EndPartAX), Pos('*', EndPartAX)) - 1);
AXStart := AXStart + Length(SubAX);
EndPartABC := Copy(ABC, ABCStart, ABCLen - ABCStart + 1);
// 比對位置:Temp=1 表示前面有 *,可任意位置搜尋;否則必須從開頭比對
if ((Pos(SubAX, EndPartABC) > 0) and (Temp = 1)) or
((Pos(SubAX, EndPartABC) = 1) and (Temp = 0)) then
begin
if Temp = 1 then Temp := 0;
ABCStart := ABCStart + Pos(SubAX, EndPartABC) + Length(SubAX) - 1;
end
else
begin
// 回溯:前面有 * 時,嘗試下一個字元位置
if (Temp = 0) and (AXWWW > 1) then
begin
AXStart := AXWWW;
Inc(ABCWWW);
ABCStart := ABCWWW;
Temp := 1;
Continue;
end;
Result := False; Break;
end;
end;
end;
// 來源字串未盡但模式已盡且結尾非 *
if Result and (ABCStart <= ABCLen) and (AX[AXLen] <> '*') then
Result := False;
end;
function IsLike(const ABC, AX: String): Boolean;
begin Result := IsABClikeAX(ABC, AX); end;
function WideCard(const ABC, AX: String): Boolean;
begin Result := IsABClikeAX(UpperCase(ABC), UpperCase(AX)); end;
MatchesMask ~ 20+ 秒。MatchesMask,效能瓶頸時再換自訂版本。if WideCard('FileName.txt', '*.txt') then ShowMessage('符合');
if IsLike('ABC123', 'ABC?23') then ShowMessage('符合');