如何修復 Java 中的 PatternSyntaxException:“索引附近非法重複”
1.概述
Java 正規表示式中很少有問題像遇到“java.util.regex.PatternSyntaxException: Illegal repetition near index X”.
這種常見異常發生在正規表示式量詞(控制重複的強大符號)在模式中被誤用或放置錯誤時。
因此,正規表示式雖然是模式匹配、驗證和解析的重要工具,但由於其語法複雜,使用起來可能會變得非常困難。因此,誤用量詞可能會導致可見的異常和隱藏的匹配問題。
在本教程中,我們將探討此異常的含義,檢查其常見原因,最重要的是,展示如何修復它,以使我們的正規表示式模式順利運行。
2. 理解異常
每當正規表示式模式包含語法錯誤時,Java 都會拋出PatternSyntaxException
,從而停止該模式的編譯。特定的“Illegal repetition near index”
訊息表示正規表示式中的某個重複運算子(量詞)使用或放置不正確。
在深入研究修復之前,有必要重新認識正規表示式中常見的量詞:
-
'*'
匹配前一個元素零次或多次 -
'+'
匹配一次或多次 -
'?'
匹配零次或一次 -
'{n}
' 匹配 n 次 -
'{n,}'
匹配 n 次或更多次 -
'{n,m}'
匹配 n 到 m 次
每個量詞都作用於緊接在其前面的元素,無論是字元、群組或字元類別。
但是,當量詞在模式中的位置不正確或使用無效語法(例如缺少括號或轉義不正確)時,就會發生此異常。
因此,理解量詞背後的嚴格語法規則對於防止這種錯誤至關重要。
3. 什麼原因導致正規表示式出現「非法重複」?
此異常可能由正規表示式模式中與量詞相關的各種常見錯誤所引起。我們將分析最常見的原因及其解決方法,並附帶範例。
3.1. 孤立量詞
量詞必須位於有效的字元、字元組或字元類別之後。如果它出現在模式的開頭或位於無效元素之後,則它沒有任何作用,並會導致錯誤:
Pattern.compile("*[az]"); // Invalid: orphaned quantifier
在此範例中,星號位於任何有效元素之前,因此引擎無法確定要重複的內容。為了修正這個問題,我們確保量詞位於有效的目標之後:
Pattern.compile("[az]*abc"); // Valid
我們必須始終仔細檢查量詞是否是孤立的或位於開頭。
3.2. 不帶分組的嵌套量詞
不允許將一個量詞直接放在另一個量詞之後而不進行分組。如果量詞堆疊不清晰,引擎將無法正確解釋該模式:
Pattern.compile("\\d+\\.?\\d+*"); // Invalid: nested quantifiers without grouping
這裡,'*' 量詞試圖不經過分組就直接應用於 '\\d+',這是非法操作。正確的方法是將量化表達式分組,以便外部量詞應用於整個重複:
Pattern.compile("\\d+(\\.\\d+)*"); // Valid
分組可以明確量化的內容,避免歧義和語法錯誤。
3.3. 未閉合或畸形的花括號
花括號用於指定精確或範圍的重複次數。它們必須遵循正確的語法。如果括號未閉合或格式錯誤,則會導致PatternSyntaxException
:
Pattern.compile("\\d{2,"); // Invalid: unclosed curly brace
此範例不完整,正規表示式引擎無法解析重複指令。若要修復此問題,請使用格式正確的範圍:
Pattern.compile("\\d{2,4}"); // Valid
我們也應避免在花括號中使用不完整的重複範圍或缺少的數字,例如 Java 不接受的「d{,4}」。
3.4 量化不可重複或不適當的元素
量詞必須作用於有效且完整的元素。當一個量詞緊接著另一個量詞放置時,引擎無法解釋該模式,除非第一部分被分組:
Pattern.compile("\\w+\\s+*"); // Invalid: improper quantification
在這種情況下,'*' 量詞會嘗試在 '\\s' 上應用其前面的量詞 '+',而不進行分組,這是無效的。解決方案是將量化表達式括在括號中:
Pattern.compile("(\\w+\\s+)*"); // Valid
這告訴正規表示式引擎將第二個量詞應用於整個分組重複。
3.5. 轉義文字量詞
有時,我們需要將量詞符號作為文字字元而不是正規表示式運算符進行匹配。忘記轉義會導致正規表示式引擎將其視為量詞,如果誤用,可能會導致錯誤:
Pattern.compile("abc+*"); // Invalid: unescaped literal quantifiers
在這種情況下,意圖可能是匹配文字字串“abc+*”,但模式失敗,因為“*”被視為應用於“c+”的量詞。為了匹配這些符號,必須對其進行轉義,而在 Java 字串中,這需要使用雙反斜線:
Pattern.compile("abc\\+\\*"); // Valid
正確的轉義可確保正規表示式引擎將這些字元視為文字,而不是運算符。
4. 避免此異常的最佳實踐
為了避免與非法重複相關的PatternSyntaxException
,我們可以遵循一些最佳實踐:
- 始終將量詞放在有效標記(字元、字元類別或字元組)之後
- 切勿以量詞作為正規表示式模式的開頭
- 當將多個量詞應用於同一部分時,使用括號將元素分組
- 確保所有括號量詞都完整書寫,包括左括號和右括號
- 當目標是逐字匹配時,轉義特殊字符
- 利用異常訊息中的索引快速定位錯誤
- 使用值得信賴的線上正規表示式測試工具測試並驗證正規表示式模式
- 動態建立正規表示式模式時,清理輸入並驗證最終模式
5. 結論
“PatternSyntaxException: Illegal repetition near index”
是使用 Java 正規表示式時經常遇到的錯誤。幸運的是,它通常很容易解決。此異常通常是由於量詞位置不正確、語法格式錯誤或嘗試將量詞應用於不可重複的元素(例如錨點或某些特殊字元)引起的。
掌握量詞的用法並系統地回顧其模式有助於有效地排除這些錯誤。需要驗證的重要面向包括:確保量詞的位置正確、重複範圍正確閉合以及特殊字元得到適當的轉義。
與往常一樣,文章中的程式碼可在 GitHub 上取得。