量詞、錨點


如果想使用者輸入的手機號碼格式是否為 XXXX-XXXXXXX,其中 X 為數字,雖然規則表示式可以使用 \d\d\d\d-\d\d\d\d\d\d,不過更簡單的寫法是 \d{4}-\d{6}{n} 是貪婪量詞(Greedy quantifier)表示法的一種,表示前面的項目出現 n 次。

底下列出可用的貪婪量詞:

  • X?:X 項目出現一次或沒有
  • X*:X 項目出現零次或多次
  • X+:X 項目出現一次或多次
  • X{n}:X 項目出現 n 次
  • X{n,}:X 項目至少出現 n 次
  • X{n,m}:X 項目出現 n 次但不超過 m 次

貪婪量詞之所以貪婪,是因為看到貪婪量詞時,比對器(Matcher)會儘可能地吃掉符合的文字,然後再逐步吐出(back-off)文字給量詞後的表示式匹配。

簡單來說,貪婪量詞會儘可能地找出長度最長的符合文字

例如文字 xfooxxxxxxfoo,若使用規則表示式 .*foo 比對,在看到 .* 時,比對器儘可能地吃掉了整個 xfooxxxxxxfoo,因為都是符合 .*,接著比對器逐步吐出文字,在吐出了最尾端的 foo 時,符合了 .*foo,所以得到的符合字串就是整個 xfooxxxxxxfoo。

如果在貪婪量詞表示法後加上 ?,將會成為逐步量詞(Reluctant quantifier),又常稱為懶惰量詞,或非貪婪(non-greedy)量詞(相對於貪婪量詞來說),比對器看到逐步量詞時,會儘可能地吃掉最少量符合的文字,也就是在逐一吃下剩餘文字時,只要能符合逐步量詞,就馬上使用量詞後的表示式,逐一比對剩餘文字。

簡單來說,逐步量詞會儘可能地找出長度最短的符合文字

例如文字 xfooxxxxxxfoo 若用規則表示式 .*?foo 比對,比對器在吃掉 x 之後發現就符合了 .*,於是使用 foo 來比對剩餘文字,在逐一吃下 foo 後,也發現符合 foo 部份,於是得到第一個符合文字 xfoo;接著繼續逐一吃掉 xxxxxx,因為一直都找不到可符合 f 的文字,於是這些 x 都以 .* 來符合,直到吃到 foo 發現逐一符合 foo,於是得到第二個符合的 xxxxxxfoo 文字。

有些工具或語言支援獨吐量詞(Possessive quantifier),例如 Java(然而 Python、JavaScript 不支援),也就是在貪婪量詞表示法後加上 +獨吐量詞會儘可能地找出長度最長的符合文字,與貪婪量詞的差別在於,獨吐量詞不但貪婪且獨佔,不會再回吐文字

例如文字 xfooxxxxxxfoo,若使用規則表示式 .*+foo 比對,在看到 .* 時,比對器儘可能地吃掉了整個 xfooxxxxxxfoo,因為都是符合 .*,然而這時已經沒有剩餘文字可以匹配剩下的 foo 表示式,所以結果就是沒有任何文字符合。

如果使用規則表示式 x++foox+ 一開始儘可能地吃掉的 x 只有一個,接著使用 foo 來比對 fooxxxxxxfoo,於是一開頭的 foo 符合,結果得到第一組符合文字 xfoo,接著剩下的 xxxxxxfoo,x+ 儘可能地吃掉了六個 x,剩下 foo 符合 foo 部份,於是得到第二組符合文字 xxxxxxfoo。

對於文字 xfooxxxxxxfoo,就結果而言,.*?foox++foo 雖然都符合到 xfoo 與 xxxxxxfoo 兩組文字,然而過程並不相同。

如果有個文字 Justin dog Monica doggie Irene,使用表示式 dog 的話,會符合到 dog 與 doggie 前的 dog 部份:

量詞、錨點

你可以使用 \b 標出單字邊界,例如 \bdog\b,這就只會比對出 dog 單字:

量詞、錨點

邊界比對用來表示文字必須符合指定的邊界條件,也就是定位點,因此這類表示式也常稱為錨點(Anchor),底下列出規則表示式中可用的邊界比對:

  • ^:一行開頭
  • $:一行結尾
  • \b:單字邊界
  • \B:非單字邊界
  • \A:輸入開頭
  • \G:前一個符合項目結尾
  • \Z:非最後終端機(final terminator)的輸入結尾
  • \z:輸入結尾