首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

Delphi 通配符比對函數:自訂 IsLike 與內建 MatchesMask

     編輯:Delphi

前言

Delphi 內建 MatchesMask (在 Masks 單元) 支援 * (多字元) 與 ? (單字元) 通配符比對。但早期版本或特定效能需求下,開發者可能需要自行實作。本文介紹一個自訂函數 IsABClikeAX,支援大小寫敏感/不敏感、中文、效能優化。

自訂函數特色

  • 非遞迴演算法,避免堆疊溢位,大多數情況比遞迴與 MatchesMask 快。
  • 正確處理 * 與 ? 所有組合情況。
  • 支援 Unicode (WideString) 與中文字元。
  • 提供 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;

效能測試參考

  • 測試字串:來源 100 個 '1',模式 99 個 '1' + '2'。
  • 1000 次迴圈:自訂函數 ~ 數秒;遞迴 ~ 數秒;MatchesMask ~ 20+ 秒。
  • 實際專案建議先用 MatchesMask,效能瓶頸時再換自訂版本。

使用範例

if WideCard('FileName.txt', '*.txt') then ShowMessage('符合');
if IsLike('ABC123', 'ABC?23') then ShowMessage('符合');
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved