此網站上的更多資訊 |
簡介 |
正規表示式快速開始 |
正規表示式教學 |
替換字串教學 |
應用程式和語言 |
正規表示式範例 |
正規表示式參考 |
替換字串參考 |
書籍評論 |
可列印 PDF |
關於此網站 |
RSS Feed 和部落格 |
已經介紹過一個重複運算子或量詞:問號。它告訴引擎嘗試比對前一個代幣 0 次或 1 次,實際上讓它變成可選的。
星號或加號告訴引擎嘗試比對前一個代幣 0 次或多次。加號告訴引擎嘗試比對前一個代幣 1 次或多次。 <[A-Za-z][A-Za-z0-9]*> 比對不帶任何屬性的 HTML 標籤。尖括號是字面值。第一個字元類別比對一個字母。第二個字元類別比對一個字母或數字。星號重複第二個字元類別。因為我們使用了星號,所以第二個字元類別比對不到任何東西也是可以的。因此,我們的正規表示式會比對像 <B> 這樣的標籤。在比對 <HTML> 時,第一個字元類別會比對 H。星號會讓第二個字元類別重複 3 次,在每個步驟中比對 T、M 和 L。
我也可以使用 <[A-Za-z0-9]+>。我沒有這樣做,因為這個正規表示式會配對 <1>,這不是一個有效的 HTML 標籤。但如果你知道你正在搜尋的字串不包含任何此類無效標籤,這個正規表示式可能就足夠了。
有一個額外的量詞允許你指定一個代碼可以重複多少次。語法是 {最小值,最大值},其中 最小值 是零或正整數,表示最少配對次數,而 最大值 是等於或大於 最小值 的整數,表示最多配對次數。如果逗號存在但省略了 最大值,則最多配對次數是無限的。所以 {0,1} 與 ? 相同,{0,} 與 * 相同,而 {1,} 與 + 相同。省略逗號和 最大值 會告訴引擎重複代碼恰好 最小值 次。
你可以使用 \b[1-9][0-9]{3}\b 來配對介於 1000 到 9999 之間的數字。\b[1-9][0-9]{2,4}\b 配對介於 100 到 99999 之間的數字。請注意使用 字詞邊界。
假設你想要使用正規表示式來配對 HTML 標籤。你知道輸入會是一個有效的 HTML 檔案,所以正規表示式不需要排除任何無效使用尖括號的情況。如果它位於尖括號之間,它就是一個 HTML 標籤。
大多數剛接觸正規表示式的人會嘗試使用 <.+>。當他們在像 這是個 <EM>第一個</EM> 測試 的字串上測試它時,他們會感到驚訝。你可能會期望正規表示式配對 <EM>,然後在該配對後繼續配對 </EM>。
但它沒有。正規表示式會配對 <EM>第一個</EM>。顯然不是我們想要的。原因是加號是貪婪的。也就是說,加號會導致正規表示式引擎盡可能重複前一個代碼。只有當這導致整個正規表示式失敗時,正規表示式引擎才會回溯。也就是說,它會回到加號,讓它放棄最後一次迭代,並繼續執行正規表示式的其餘部分。讓我們深入了解正規表示式引擎,詳細了解它是如何運作的,以及為什麼這會導致我們的正規表示式失敗。在那之後,我會向你展示兩個可能的解決方案。
與加號一樣,星號和使用大括號的重複都是貪婪的。
Regex 中的第一個符號是 <。這是一個 字面。正如我們所知,它將匹配的第一個位置是字串中的第一個 <。下一個符號是句點,它匹配除了換行符號之外的任何字元。句點會被加號重複。加號是貪婪的。因此,引擎會盡可能重複句點。句點匹配 E,因此 Regex 會繼續嘗試使用下一個字元匹配句點。M 已匹配,而句點會再重複一次。下一個字元是 >。現在你應該看出問題了。句點匹配 >,而引擎會繼續重複句點。句點將匹配字串中所有剩餘的字元。當引擎到達字串結束後的空隙時,句點會失敗。只有在這個時候,Regex 引擎才會繼續下一個符號:>。
到目前為止,<.+ 已匹配 <EM>first</EM> test,而引擎已到達字串的結尾。> 無法在此處匹配。引擎會記住加號重複句點的次數比要求的次數多。(請記住,加號要求句點只匹配一次。)引擎不會承認失敗,而是會回溯。它會將加號的重複次數減少一次,然後繼續嘗試 Regex 的其餘部分。
因此,.+ 的匹配已減少為 EM>first</EM> tes。Regex 中的下一個符號仍然是 >。但現在字串中的下一個字元是最後一個 t。同樣地,它們無法匹配,導致引擎進一步回溯。到目前為止的總匹配已減少為 <EM>first</EM> te。但 > 仍然無法匹配。因此,引擎會繼續回溯,直到 .+ 的匹配減少為 EM>first</EM。現在,> 可以匹配字串中的下一個字元。Regex 中的最後一個符號已匹配。引擎報告 <EM>first</EM> 已成功匹配。
請記住,Regex 引擎急於回傳匹配。它不會繼續進一步回溯以查看是否有另一個可能的匹配。它會報告找到的第一個有效匹配。由於貪婪,這是最左邊最長的匹配。
解決此問題的快速方法是讓加號變懶惰而非貪婪。懶惰量詞有時也稱為「非貪婪」或「不情願」。你可以在 regex 中的加號後加上問號來做到這一點。你也可以對星號、大括號和問號本身執行相同的操作。因此,我們的範例會變成 <.+?>。讓我們再次查看 regex 引擎內部。
同樣地,< 會比對字串中的第一個 <。下一個代幣是句點,這次由一個懶惰的加號重複。這會告訴 regex 引擎盡可能少重複句點。最小值為一。因此,引擎會將句點與 E 比對。需求已滿足,引擎會繼續進行 > 和 M。這會失敗。同樣地,引擎會回溯。但這次,回溯會強迫懶惰的加號擴展,而不是減少其範圍。因此,.+ 的比對會擴展為 EM,而引擎會再次嘗試繼續進行 >。現在,> 已成功比對。regex 中的最後一個代幣已比對。引擎會報告已成功比對 <EM>。這更像它。
在這種情況下,有一個比讓加號變懶惰更好的選項。我們可以使用貪婪的加號和否定字元類別:<[^>]+>。這樣更好的原因是因為回溯。當使用懶惰的加號時,引擎必須對它嘗試比對的 HTML 標籤中的每個字元進行回溯。當使用否定字元類別時,當字串包含有效的 HTML 程式碼時,根本不會發生回溯。回溯會減慢 regex 引擎的速度。當在文字編輯器中進行單一搜尋時,你不會注意到差異。但當你在編寫的腳本中或在 EditPad Pro 的自訂語法著色方案中重複使用此類 regex 時,你會節省大量的 CPU 週期。
只有regex 導向引擎會回溯。文字導向引擎不會,因此不會受到速度懲罰。但它們也不支援懶惰量詞。
序列 \Q…\E 會跳脫字元字串,並將其視為字面字元進行比對。跳脫後的字元會被視為個別字元。如果您在 \E 後面加上量詞,它只會套用於最後一個字元。例如,如果您將 *\d+*+ 套用於 *\d+**\d+*,比對結果將會是 *\d+**。只有星號會重複。Java 4 和 5 有個錯誤,會導致整個 \Q…E 序列重複,並將整個主旨字串作為比對結果。此錯誤已在 Java 6 中修正。
| 快速入門 | 教學 | 工具和語言 | 範例 | 參考 | 書籍評論 |
| 簡介 | 目錄 | 特殊字元 | 非列印字元 | 正規表示式引擎內部 | 字元類別 | 字元類別減法 | 字元類別交集 | 簡寫字元類別 | 點 | 錨點 | 字詞邊界 | 交替 | 選用項目 | 重複 | 群組和擷取 | 反向參照 | 反向參照,第 2 部分 | 命名群組 | 相對反向參照 | 分支重設群組 | 自由間距和註解 | Unicode | 模式修改器 | 原子群組 | 佔有量詞 | 前瞻和後顧 | 前瞻和後顧,第 2 部分 | 將文字保留在比對結果之外 | 條件式 | 平衡群組 | 遞迴 | 子常式 | 無限遞迴 | 遞迴和量詞 | 遞迴和擷取 | 遞迴和反向參照 | 遞迴和回溯 | POSIX 方括號表示法 | 零長度比對 | 繼續比對 |
頁面網址:https://regular-expressions.dev.org.tw/repeat.html
頁面最後更新時間:2021 年 8 月 12 日
網站最後更新:2024年3月15日
版權所有 © 2003-2024 Jan Goyvaerts。保留所有權利。