模稜兩可的反向引用
問題: 你需要匹配某種格式的文字,例如:
1-a-0
6/p/0
4 g 0
這是一個數字,一個分隔符(-
,/
或空格之一),一個字母,相同的分隔符和一個零。
天真的解決方案: 從基礎知識示例中調整正規表示式,你想出了這個正規表示式:
[0-9]([-/ ])[a-z]\10
但那可能行不通。大多數正規表示式支援超過 9 個捕獲組,並且很少有人足夠聰明地意識到,因為只有一個捕獲組,\10
必須是對第 1 組的反向引用,然後是文字 0
。大多數口味會將其視為對第 10 組的反向引用。其中一些會引發例外,因為沒有第 10 組; 其餘的根本無法匹配。
有幾種方法可以避免這個問題。一種是使用命名組 (並命名為反向引用):
[0-9](?<sep>[-/ ])[a-z]\k<sep>0
如果你的正規表示式語言支援它,則\g{n}
(其中 n
是數字)的格式可以將反引用數字括在大括號中,以將其與後面的任何數字分開:
[0-9]([-/ ])[a-z]\g{1}0
另一種方法是使用擴充套件的正規表示式格式,用無關緊要的空格分隔元素(在 Java 中你需要轉義括號中的空格):
(?x) [0-9] ([-/ ]) [a-z] \1 0
如果你的正規表示式不支援這些功能,你可以新增不必要但無害的語法,如非捕獲組:
[0-9]([-/ ])[a-z](?:\1)0
…或虛擬量詞(這可能是 {1}
有用的唯一情況):
[0-9]([-/ ])[a-z]\1{1}0