模棱两可的反向引用
问题: 你需要匹配某种格式的文本,例如:
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