regex_replace 是否有支持内联代码的变体?

Is There a Variant of regex_replace that Supports Inline Code?

Perl 具有 e 正则表达式修饰符,它允许 Perl 代码而不仅仅是字符串来制定替换:http://perldoc.perl.org/perlretut.html#Search-and-replace 虽然这个例子不是最好的,因为有一些开关可以实现这个。对于那些了解 Perl 的人来说,这里有一个更有意义的例子:

$string = "Whosebug user: Jonathan Mee";

$string =~ s/:\s*(.*)$/ == "Jonathan Mee" ? ": ".." is AWESOME!" : ": ".." is ???"/e;

print $string; #Will print "Whosebug user: Jonathan Mee is AWESOME!"

C++ 中是否有 regex_replace 变体允许我做类似的事情?如替换代码内联。

regex_replace 有 6 种不同的重载。 fmt 参数对每个参数的使用方式相同:

A string with the replacement for each match. This may include format specifiers and escape sequences that are replaced by the characters they represent.

6 个重载中的每一个还带有一个 flags 参数用于控制,"how fmt is formatted." fmt 相关选项是:

  • format_default: 默认格式
    使用标准格式规则替换匹配项(ECMAScript 的替换方法使用的规则)。
  • format_sed sed 格式化
    使用与 POSIX 中的 sed 实用程序相同的规则来替换匹配项。
  • format_no_copy没有复制
    替换匹配时不复制目标序列中与正则表达式不匹配的部分。
  • format_first_only第一只
    仅替换第一次出现的正则表达式。

请注意,fmt 重载的 none 和 flags 都不支持内联代码。所以答案是:不,regex_replace没有支持内联代码的变体。


但是,如果您愿意将 STD 算法与 regex_iterator 结合使用,则可以使用 lambda 来完成内联代码。

const string foo("Whosebug user: Jonathan Mee");
vector<string> bar;

transform(regex_iterator<string::const_iterator>(foo.cbegin(), foo.cend(), regex(".*:\s*(.*)")),
          regex_iterator<string::const_iterator>(),
          back_inserter(bar),
          [](const smatch& i){auto result = i.str();

                              if (!result.empty()){
                                  result += (i.str(1) == "Jonathan Mee" ? " is AWESOME!" : " is ???");
                              }
                              return result;});

如您所见,lambda 在 transform 中可用,用于当前 regex_iteratorsmatch。这对于多行字符串非常可扩展,在 string foo("Whosebug user: Jonathan Mee\nWhosebug user: user0"); 的示例中,输出将是:

Whosebug user: Jonathan Mee is AWESOME!
Whosebug user: user0 is ???

显然,仅 smatchregex_replace 之间存在一些权衡。未指定 str(1) 属于 str() 的位置。在这里,我利用了它就在 foo 末尾的事实,而不是必须在 foo 中间找到的某个地方。但应该提到的是,同样的困难也降临在 Perl 的 e-修饰符上,所以我认为这非常相似。