GCC和MSVC在std::regex_replace行为上的差异

3

我正在尝试实现一种用于正则表达式匹配的字符串转义方法。

不幸的是,我发现编译器之间存在不一致性。使用GCC 7.1和Visual Studio 2015U3编译此代码(添加了boost实现以进行比较)会产生不同的结果:

#include <iostream>
#include <regex>
#include <string>
#include <boost/regex.hpp>

std::string regexEscape(const std::string& s)
{
    return std::regex_replace(s, std::regex{ R"([\^\.\$\|\{\}\(\)\[\]\*\+\?\/\\])" }, std::string{ R"(\\\1&)" }, std::regex_constants::match_default | std::regex_constants::format_sed);
}

std::string boostRegexEscape(const std::string& s)
{
    return boost::regex_replace(s, boost::regex{ R"([\^\.\$\|\{\}\(\)\[\]\*\+\?\/\\])" }, std::string{ R"(\\\1&)" }, boost::match_default | boost::format_sed);
}

int main()
{
    std::string test{ R"(123.456^789$123\456|789*123+456(789)123?456)" };
    std::cout << regexEscape(test) << '\n';
    std::cout << boostRegexEscape(test) << '\n';
}

GCC:

123\\.456\\^789\\$123\\\456\\|789\\*123\\+456\\(789\\)123\\?456
123\.456\^789\$123\\456\|789\*123\+456\(789\)123\?456

MSVC:

123\.456\^789\$123\\456\|789\*123\+456\(789\)123\?456
123\.456\^789\$123\\456\|789\*123\+456\(789\)123\?456

这是预期行为吗?

{btsdaf} - Wiktor Stribiżew
{btsdaf} - DaveM
{btsdaf} - Wiktor Stribiżew
{btsdaf} - DaveM
{btsdaf} - Wiktor Stribiżew
{btsdaf} - DaveM
1个回答

1
您要求正则表达式引擎使用R"(\\\1&)"进行替换,这是一个\\\1&替换模式,将其视为sed替换模式。在sed中,&代表整个匹配。由于模式中没有ID为1的组,因此\1指代空字符串。当使用Boost时,前两个反斜杠被解析为单个反斜杠,必须转义Boost替换模式中的字面反斜杠才能使用单个字面反斜杠作为替换。

Sed风格的格式字符串将所有字符视为字面量,除非:

&和正则表达式匹配的整个字符串会在输出流中被替换。使用\&可以输出字面'&'字符。

\ 指定转义序列。

至于替换模式的其余部分,它将起到相同的作用。

您可以使用

 std::regex_replace(s, std::regex{ R"(([.^$|{}()[\]*+?/\\]))" }, std::string{ R"(\$1)" }, std::regex_constants::match_default);

使用Boost,可以使用相同的方法/选项来实现结果的一致性。在这里,使用默认引擎。
关于MSVC和GCC之间的差异,有关文档很少。显然,在两个编译器中定义文字反斜杠的行为是不同的。请注意,许多正则表达式库将文字反斜杠视为正则表达式转义(与Boost中的情况相同,请参见上面的参考),要定义文字替换反斜杠,您需要在替换模式中加倍文字反斜杠。您在GCC中使用的引擎是ECMAScript
似乎定义回溯替换模式的方式是由每个正则表达式替换实现决定的。当您在GCC中使用它时,单个文字“\”(=“\\”)将被视为单个文字替换反斜杠。MSVC编译器决定跟随大多数正则表达式引擎,并且 - 当您使用std :: regex_constants :: format_sed时可以使用替换反向引用作为\1-\9 - 需要转义文字替换反斜杠并替换为单个“\”,您需要使用两个文字反斜杠,“\\\\”(或R”(\\)“)。

{btsdaf} - DaveM
{btsdaf} - Wiktor Stribiżew
{btsdaf} - DaveM
{btsdaf} - DaveM
1
{btsdaf} - Wiktor Stribiżew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接