【问题标题】:C++11 regex: digit after capturing group in replacement stringC++11 正则表达式:在替换字符串中捕获组后的数字
【发布时间】:2015-06-30 20:00:44
【问题描述】:

我的 regex_replace 表达式在替换字符串中的“0”字符之前使用组 $1,如下所示:

#include <iostream>
#include <string>
#include <regex>

using namespace std;

int main() {
    regex regex_a( "(.*)bar(.*)" );
    cout << regex_replace( "foobar0x1", regex_a, "$10xNUM" ) << endl;
    cout << regex_replace( "foobar0x1", regex_a, "$1 0xNUM" ) << endl;
}

输出是:

xNUM
foo 0xNUM

我正在尝试在没有中间空格的情况下获得输出 foo0xNUM

如何保护组名 $1 免受替换字符串中的下一个字符的影响?

【问题讨论】:

  • 这真令人气愤。我的第一个想法是使用 ${1},但这不受支持。我的下一个想法是使用一个命名的捕获组——这是不被支持的。我真的很好奇正确答案。
  • @timgeb - 是的,我正在从 boost::regex 迁移 ${1} 工作正常。

标签: c++ regex c++11 regex-group


【解决方案1】:

您可以指定$n$nn 来引用捕获的文本,因此您可以使用$nn 格式(此处为$01)来避免抓取0

cout << regex_replace( "foobar0x1", regex_a, "$010xNUM" ) << endl;

【讨论】:

    【解决方案2】:

    Guvante 已为此问题提供了a solution

    但是,行为是否根据规范进行了良好定义?

    从结论开始。 是的,该解决方案具有明确定义的行为。

    C++ 规范

    format_default 的文档指定了 ECMA 规则来解释格式字符串,指向 ECMA-262 的第 15.5.4.11 节。

    ECMA-262 规范

    根据Section 15.5.4.11 of ECMA-262 specification中的表22

    $n

    第 n 次捕获,其中 n 是 1 到 9 范围内的单个数字,$n 后面没有十进制数字。如果 n ≤ m 并且第 n 次捕获未定义,请改用空字符串。如果 n > m,则结果是实现定义的。

    $nn

    第 nn 次捕获,其中 nn 是 01 到 99 范围内的两位十进制数。如果 nn ≤ m 并且第 nn 次捕获未定义,请改用空字符串。如果 nn > m,则结果是实现定义的。

    变量 m 在同一节的上一段中定义:

    [...] 设 m 为 searchValue 中左捕获括号的数量(使用 15.10.2.1 中指定的 NcapturingParens)。

    问题"$10xNUM"中的替换字符串

    回到问题中的代码:

    cout << regex_replace( "foobar0x1", regex_a, "$10xNUM" ) << endl;
    

    由于$1后面跟着0,它必须被解释为第二条规则$nn,因为第一条规则禁止任何数字跟随$n。但是,由于该模式只有 2 个捕获组 (m = 2) 和 10 > 2,因此行为是根据规范实现定义的

    我们可以通过比较Firefox 37.0.1中功能等效的JavaScript代码的结果来看到实现定义子句的效果:

    > "foobar0x1".replace(/(.*)bar(.*)/g, "$10xNUM" )
    < "foo0xNUM"
    

    如您所见,Firefox 决定将$10 解释为获取第一个捕获组$1 的值,然后是固定字符串0。这是根据规范在$nn 子句中的条件下的有效实现。

    Guvante 回答中的替换字符串:"$010xNUM"

    同上,使用$nn 子句,因为$n 子句禁止任何数字跟随。由于$01中的01小于捕获组的数量(m = 2),所以行为很明确,就是在替换中使用捕获组1的内容。

    因此,Guvante 的回答将在任何抱怨的 C++ 编译器上返回相同的结果。

    【讨论】:

      【解决方案3】:

      我试图找到一种简单地转义空间或其他东西的方法,以便它不会打印,但我做不到。

      但是,您尝试添加的位可以简单地附加到正则表达式输出的末尾:

      cout << regex_replace( "foobar0x1", regex_a, "$1" ) << "0xNUM" << endl;
      

      上面的行会给你你想要的输出。

      【讨论】:

      • 谢谢米加拉。虽然这个例子是正确的,但在我的真实代码中追加不是一个选项。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-24
      • 2012-04-26
      • 1970-01-01
      • 2012-08-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多