将gcc从版本4.8.5升级到版本5.3.1后,我想我 可以摆脱boost的正则表达式实现(升级版本1.54.0)和 使用gcc提供的那个(在版本4.9之前它没有使用gcc 据我所知)。然而,事实证明这是一个问题,因为那两个 实现的行为不同:
#include <regex>
#include <boost/regex.hpp>
#include <iostream>
#include <string>
int main() {
std::string s="\\needs_another_backslash";
std::string reg("^(\\\\)(needs)(.+)");
std::string rep("\\\\got$3");
std::regex sr(reg);
boost::regex br(reg);
std::cout<<"string before replacement:\n"<<s<<std::endl<<
"regular expression:\n"<<reg<<std::endl<<
"replacement string:\n"<<rep<<std::endl<<
"std::regex_replace:\n"<<std::regex_replace(s,sr,rep)<<std::endl<<
"boost::regex_replace:\n"<<boost::regex_replace(s,br,rep)<<std::endl;
return 0;
}
这给出了以下输出:
string before replacement:
\needs_another_backslash
regular expression:
^(\\)(needs)(.+)
replacement string:
\\got$3
std::regex_replace:
\\got_another_backslash
boost::regex_replace:
\got_another_backslash
好像提升对待&#39; \&#39;特别是在替换字符串中 而gcc没有。由于std :: regex_replace的替换字符串中的反向引用的神奇字符是&#39; $&#39; (它也是作为示例证明的提升),我倾向于认为gcc是对的。然而,在许多其他程序(例如vim)中,它是&#39; \。因此,提升可能有助于治疗&#39; \&#39;特别。那么谁是对的?
答案 0 :(得分:0)
首先,std示例实际上不是gcc的问题,而是C ++标准的问题,gcc(在本例中)是兼容的。标准在28.5.2中说明:
当正则表达式匹配由新字符串替换时,新的 string应使用ECMAScript replace使用的规则构造 ECMA-262中的函数,第15.5.4.11节String.prototype.replace。此外, 在搜索和替换操作期间所有非重叠的出现 应定位和替换正则表达式,并输入部分 与表达式不匹配的表达式应不加改变地复制到输出中 字符串。
并且ECMA声明:
否则,让newstring表示将replaceValue转换为String的结果。结果是从原始输入String派生的String值,方法是将每个匹配的子字符串替换为从newstring派生的字符串,方法是用表22中指定的替换文本替换newstring中的字符。这些$替换是从左到右完成的,并且,一旦进行了这样的替换,新的替换文本不再需要进一步替换。例如,“$ 1,$ 2”.replace(/(\ $(\ d))/ g,“$$ 1- $ 1 $ 2”)返回“$ 1- $ 11,$ 1- $ 22”。与以下任何表格都不匹配的新闻字符串中的$保留原样。
(如果part:replaceValue是一个函数。)
没有提到有关替换转义序列的内容。用firefox试过:
var test = "\\needs_another_backslash";
test = test.replace(/^(\\)(needs)(.+)/, "\\\\got$3");
alert(test);
结果:\\got_another_backslash
。
提升documentation州:
效果:如果fmt是以null结尾的字符串或char_type的容器,则将字符序列[fmt.begin(),fmt.end())复制到OutputIterator out。对于fmt中的每个格式说明符或转义序列,将该序列替换为它所代表的字符,或者它所引用的* this中的字符序列。 flags中指定的位掩码确定识别哪些格式说明符或转义序列,默认情况下,这是ECMA-262,ECMAScript语言规范,第15章第5.4.11节String.prototype.replace使用的格式。
此外,它还声明了match_type_flags:
指定在用新字符串替换正则表达式匹配时,使用ECMA-262中ECMAScript替换函数使用的规则构建新字符串,ECMAScript语言规范,第15章第5.4.11节字符串.prototype.replace。 (FWD.1)。
这在功能上与Perl格式字符串规则相同。
[...]
在linux上尝试使用perl 5.18.2:
my $test = "\\needs_another_backslash";
$test =~ s/^(\\)(needs)(.+)/\\\\got$3/;
print "$test\n";
导致\\got_another_backslash
。
使用std::string reg("^(\\\\)(needs)(.+)");
时,传递字符串文字时,reg会保存字符串^(\\)(needs)(.+)
(不是字面值,因此省略引号!),而std::string rep("\\\\got$3");
代表字符{hold} { {1}}。
但是在解释上显然存在差异。假设我们有std和boost两个和相同的ECMAScript引擎。
然后,std和boost一致的做法是将\\got$3
字符串编译为正则表达式:
reg
我认为通过创建std / boost :: regex类的实例可以很好地反映这一点。
然后出现差异:std将sprintf(b, "/%s/", reg);
sr /* br, respectively */ = ECMAScriptEngine::compileFromSource(b);
,s
和sr
传递给ECMAScript引擎,以便直接调用rep
(当然没有这样的现实中的s函数 - 只是让我们假设我们可以这样做。)
boost也可以编译rep字符串(旁注:我没有安装boost,所以我自己也没有验证这个行为......):
s.(String.prototype.replace)(sr, rep);
然后拨打引擎sprintf(b, "'%s'", rep); // note: '', not //!
ecma_rep = ECMAScriptEngine::compileFromSource(b);
。
有趣的是,boost不会编译源字符串s,它再次与std ...
一致最后,我认为,标准实施反映了我们实际想做的事情:
s.(String.prototype.replace)(sr, ecma_rep);
VS
s.replace(regex, string);
s.replace(/reg/, rep);
(std::string).replace(std::regex(std::string), std::string);
std::regex_replace(s, std::regex(reg), rep);
不确定这是否足以说一个是对的而另一个是错的,但是(这意味着错误的一个是错误的!)。可能我们甚至必须保留第三种选择:两种方法都是有效的(所以两种方法都是正确的,没有一种是错误的),不幸的是,它们是不相容的......