作者:施懿民
分组不仅用在匹配结果中,也可以在匹配的正则表达式中使用分组匹配的结果,这种功能称为反向引用(Backreference)。当待匹配的字符串中有些子字符串出现多次的话,正则表达式模式可以将第一个出现的子字符串保存在分组中,在模式的后面可以直接引用第一个匹配的结果。因为分组即可通过索引也可以通过名字来访问,所以反向引用里也有索引版和名字的版本:
根据索引反向引用的语法为:“umber”,number是分组在正则表达式中的位置,从1开始计数。如代码清单 3 - 8中第9行的模式“(w+)s(1)”,1即表示反向引用第一个分组“(w+)”的匹配结果,由于在后面的第13行需要将“1”当作一个新的分组使用 – match.Groups[2],所以使用括号将模式创建了一个新分组,否则的话括号是可以省略的。
在正则表达式里,“1”到”9”永远被解析成索引反向引用语法,如果使用的分组索引不存在,会导致正则表达式引擎抛出ArgumentException异常,如“(w+)s2”就会导致异常,因为“2”前面只有一个分组“(w+)”。“10”及以上只有在分组数足够的话才会被当作索引反向引用,否则会被当作普通的八进制数字进行匹配,不过也不建议读者在写太复杂的正则表达式,造成调试和代码阅读上的困难。
在Visual Studio Code等编辑器里同样是支持反向引用的,图 3 - 7中使用模式“(d+)(-)12“成功匹配“2009-09-09”这个字符串,而不能匹配“2018-12-31”,这是因为”1”对应的是第一个分组:“(d+)”,”2”对应的是第二个分组“(-)”。
![3ac4bf02115cac86dc79807c8d7f6f1c.png](https://img-blog.csdnimg.cn/img_convert/3ac4bf02115cac86dc79807c8d7f6f1c.png)
图 3 - 7在VS Code里使用反向引用
如果给分组命名过的话,使用命名反向引用就方便得多,命名反向引用的语法可以是:“k”或“k'name'”,其中name就是分组的名字。代码清单 3 - 8中第10行就演示这种使用方法,首先定义了一个“”分组用来匹配一个单词,再使用“k”反向引用前面匹配的结果,从而找出重复的单词。
替换
正则表达式除了可以用来在输入字符串中匹配和提取子字符串以外,还可以用在字符串替换中,在Regex.Replace方法中可以使用替换(Substitution)模式来使用匹配结果进行替换操作,这个方法有一个replacement参数,在replacement参数中可以使用替换模式。替换模式以字符“$”开头,通常跟分组一起使用,与反向引用类似,支持按索引和按命名来使用分组匹配结果。如代码清单 3 - 14中,使用正则表达式将不同货币金额中的货币符号去掉,只留下金额的方法。在第1行的模式中:
l p{Sc}*:匹配货币符号字符,这个字符是可选的;
l (s?d+[.,]?d*):“s?”匹配零到一个空格字符,“d+[.,]?d*”匹配金额,金额的整数部分和小数部分使用点号“.”或逗号“,”分隔,不同国家表示小数的方式是不一样的,中国习惯上使用点号“.”分隔小数,而西欧一些国家如德国的习惯上使用逗号“,”分隔小数。当然这个模式有一个额外的匹配效果 – 即可以匹配按千分位表示的数字,如第4行中最后一个数字:“123,456.00”。
代码清单 3 - 14正则表达式替换模式示例
1 var pattern = @"p{Sc}*(s?d+[.,]?d*)";
2 var replacement = "$1";
3 var input = "$16.32 12.19 £16.29 €18.29 €18,29 ¥123.34 $123,456.00";
4 var result = Regex.Replace(input, pattern, replacement);
5 Console.WriteLine(result);
6
7 pattern = @"p{Sc}*(?s?d+[.,]?d*)";
8 replacement = "${amount}";
9 result = Regex.Replace(input, pattern, replacement);
10 Console.WriteLine(result);
如果模式成功匹配,第2行中的“$1”保存的是第一个分组匹配的结果,数字“1”是分组的索引,跟反向引用类似,正则表达式中的分组索引是从1开始的。第7行使用与第1行相同的模式,只不过命名匹配金额的分组为“amount”,因此在第8行的替换模式中可以直接使用名称“amount”来使用匹配结果。
表 3 - 5 .NET中的正则表达式替换模式说明
![1126a33a3bf3b5c6073ce301a25091aa.png](https://img-blog.csdnimg.cn/img_convert/1126a33a3bf3b5c6073ce301a25091aa.png)
在Visual StudioIDE和Visual Studio Code等文本编辑器中,也可以直接使用替换模式来提高编辑效率,如笔者经常将Excel、网页等地方拷贝的文字列表转换成源代码中的字符串数组,就会用到替换模式技巧。如图 3 - 8中,在查找文本框中使用“^(.+)$”模式来匹配每一行的完整字符串,在替换文本框中,模式"$&