在前两节中,我们了解了如何在字符串或字符串的一部分上匹配正则表达式,并遍历匹配项和子匹配项。同样,正则表达式库还支持基于正则表达式的文本替换功能。在本节中,我们将学习如何使用std::regex_replace()来进行这样的文本转换。
有关C++11支持正则表达式的相关内容,请参阅2.9节。
为了使用正则表达式进行文本转换,应该执行以下操作:
❍ 包含头文件<regex>和<string>以及命名空间std::string_literals(C++14标准字符串可以使用的用户自定义字面量):
❍ 使用std::regex_replace()算法,并将替换字符串作为第三个参数。可以参考下面的示例,用3个“-”字符替换所有由a、b或c三个字符组成的单词:
❍ 使用std::regex_replace()算法,将$开头的标识符作为第三个参数。例如,将格式为“lastname, firstname”的名字替换成格式为“firstname lastname”的名字,如下所示:
std::regex_replace()算法有几个重载版本,它们有着不同类型的参数,参数的含义如下:
❍ 要进行替换的输入字符串。
❍ std::basic_regex对象,它封装了用于标识要替换的字符串部分的正则表达式。
❍ 用于替换的字符串格式。
❍ 可选的匹配标志。
根据所使用的重载类型,返回值要么是字符串,要么是作为参数的输出迭代器的副本。用于替换的字符串格式可以是一个简单的字符串或匹配标识符,用$前缀表示:
❍ $&表示完全匹配。
❍ $1、$2、$3等表示第一个、第二个和第三个子匹配项,以此类推。
❍ $`表示第一个匹配项前的字符串部分。
❍ $'表示最后一个匹配项后的字符串部分。
在2.11.2节第一个例子中,初始文本包含两个由3个a、b和c字符组成的单词,即abc和bca。正则表达式表示在单词边界之间恰好有3个字符的表达式,这意味着像bbbb这样的子文本将与表达式不匹配,替换后的最终字符串文本将是--- aa --- ca bbbb。
std::regex_replace()算法可以指定额外的匹配标志。默认情况下,匹配标志是std::regex_constants::match_default,它指定ECMAScript作为构造正则表达式的基础语法。例如,如果只想替换第一个出现的匹配项,那么可以指定std::regex_constants::format_first_only。在下面的例子中,找到第一个匹配项后替换就停止了,所以最终的结果是--- aa bca ca bbbb:
然而,如前所述,替换字符串可以包含针对整个匹配、特定子匹配或未匹配部分的特殊指示符。在2.11.2节的第二个例子中,正则表达式标识单词至少有一个字符,后跟逗号和可能的空格,紧接着是至少一个字符的另一个单词。第一个单词应该是姓(Lastname),而第二个单词应该是名(firstname),替换字符串的格式为$2 $1。这是一种指令,用以将匹配的表达式(在本例中是整个原始字符串)替换成另一种形式的字符串(由第二个匹配项、空格和第一个匹配项按顺序组成)。
在本例中,整个字符串是一个匹配项。在下面的例子中,字符串中会有多个匹配项,它们都将被指定的字符串替换。在这个例子中,我们用不定冠词an替换以元音开头的单词前的不定冠词a(当然,这并不包括以元音开头的单词):
正则表达式将字母a标识为单个单词(\b表示单词边界,因此\ba表示单词只有单个字母a),该单词应后跟一个空格和一个以元音开头的至少包含两个字符的单词。当识别到这样的匹配项时,它将被替换为一个固定字符串an后跟一个空格和匹配的第一个子表达式(即单词本身)。在这个例子中,newtext字符串的值是this is an example with an error。
除了子表达式的标识符($1、$2等)之外,还有用于整个匹配的标识符($&)、用于第一个匹配项前的字符串部分的标识符($`)和用于最后一个匹配项后的字符串部分的标识符($')。在本节最后一个例子中,我们将日期的格式从dd.mm.yyyy更改为yyyy.mm.dd,同时也显示匹配的部分:
正则表达式匹配:一位或两位的数字,接着是点(.)、连字符(-)或斜杠(/);接下来是另外的一位或两位的数字,然后是点(.)、连字符(-)或斜杠(/);最后是一个四位的数字。
对于newtext1,替换字符串是$5$4$3$2$1,这意味着年后面是第二个分隔符,然后是月、第一个分隔符,最后是日。因此,对于输入字符串today is 1.06.2016!,替换后的最终结果是today is 2016.06.1!!。
对于newtext2,替换字符串是[$`][$&][$'],这意味着先是第一个匹配项之前的部分,然后是整个匹配项,最后是最后一个匹配项之后的部分,它们都在方括号中。然而,结果不是你第一眼所期望的[!!][1.06.2016][today is],而是today is[today is][1.06.2016][!!]!!,这样做是为了表示替换的仅仅是所匹配的表达式,在本例中,替换的只是日期(1.06.2016),这个字符串被原来整个字符串的另一种形式替换。
❍ 阅读2.9节,以了解C++库对正则表达式的支持。
❍ 阅读2.10节,以了解如何在文本中对一个模式进行多项匹配。