模稜兩可的反向引用

問題: 你需要匹配某種格式的文字,例如:

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