模棱两可的反向引用

问题: 你需要匹配某种格式的文本,例如:

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