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

Delphi 正則表達式語法 (6):貪婪匹配與非貪婪匹配

     編輯:Delphi

量詞 (*, +, ?, {n,m}) 預設採用「貪婪」策略:在滿足整體模式匹配的前提下,盡可能多地吞噬字元。非貪婪 (懶惰) 模式在量詞後加 ?,改為盡可能少地吞噬,只匹配滿足條件的最短字串。理解兩者差異對撰寫高效、正確的正則至關重要。

核心差異示意

量詞貪婪非貪婪描述
????0 或 1 次
+++?1 次以上
***?0 次以上
{n}{n}{n}?剛好 n 次 (非貪婪無意義)
{n,m}{n,m}{n,m}?n 到 m 次
{n,}{n,}{n,}?n 次以上

經典案例:HTML 標籤匹配

var
  reg: TPerlRegEx;
begin
  reg := TPerlRegEx.Create(nil);
  try
    reg.Subject := '標題內容';
    
    // 貪婪:<.*>  從第一個 < 吞到最後一個 >
    reg.RegEx := '<.*>';
    reg.Replacement := '◆';
    reg.ReplaceAll;
    ShowMessage(reg.Subject);  // 結果: ◆  (整串被一個標籤吞掉)
    
    reg.Subject := '標題內容';
    // 非貪婪:<.*?>  遇到第一個 > 就停止
    reg.RegEx := '<.*?>';
    reg.Replacement := '◆';
    reg.ReplaceAll;
    ShowMessage(reg.Subject);  // 結果: ◆◆◆標題◆◆◆內容◆◆ (每個標籤分別匹配)
  finally
    reg.Free;
  end;
end;

為什麼貪婪會「過度匹配」?

正則引擎採用回溯演算法:貪婪量詞先吞噬整個字串,若後續模式無法匹配,再逐字「吐出」回溯。對於 `<.*>`,.* 吞到字串末尾,發現後面沒有 > (已被吞掉),回溯到倒數第二個 > 成功,導致匹配跨越多個標籤。

非貪婪的代價與優化

  • 優點:精確控制匹配範圍,避免跨越分隔符。
  • 缺點:每次只吞一個字元再檢查後續模式,可能產生大量匹配嘗試,效能較差。
  • 最佳替代方案:使用排除字元類別 代替 .*?。例如匹配雙引號字串:"[^"]*" (無逸出) 或 "(\\"|[^"])*" (支援逸出) 比 ".*?" 快數倍,且不會跨行匹配。

實務決策指南

情境建議寫法理由
匹配雙引號字串 (無換行)"[^"]*"排除類別直達結尾,零回溯
匹配單引號字串 (支援逸出)'(\\'|[^'])*'明確處理逸出,避免非貪婪回溯
匹配 HTML 標籤內容<[^>]+>標籤不含 >,排除類別最快
分隔符不明確/多變.*? 或 .+?只能用非貪婪,注意效能
固定次數重複{n}無貪婪/非貪婪之分

災難性回溯

模式如 (a+)+b 輸入 aaaaaaaaac 會導致指數級回溯。非貪婪 (a+?)+b 同樣會回溯。解決辦法:

  1. 使用佔有優先量詞 (Possessive Quantifier):a++、*+、?+、{n,m}+ (PCRE/Perl 5.10+ 支援,Delphi TPerlRegEx 視版本而定)。
  2. 改寫為原子群組:(?>a+)。
  3. 改用排除類別或更精確模式。

Delphi TPerlRegEx 設定選項

reg.Options := reg.Options + [preSingleLine];  // . 匹配包含換行
reg.Options := reg.Options - [preGreedy];      // 全域關閉貪婪 (較少用)

建議明確在量詞後加 ? 控制非貪婪,而非依賴全域選項,以保持模式可讀性與可攜性。

總結

  1. 貪婪 = 盡量多匹配;非貪婪 = 盡量少匹配 (量詞後加 ?)。
  2. 非貪婪解決「過度吞噬」問題,但可能降低效能。
  3. 優先使用排除字元類別 ([^...]) 替代非貪婪,兼具精確與高效。
  4. 警惕災難性回溯,善用佔有優先量詞或原子群組優化。

下一篇將介紹「邊界匹配」:單字邊界、字串開頭結尾、Unicode 屬性邊界等定位技巧。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved