我正在尝试实现一个方法来转义字符串,以便与正则表达式匹配一起使用。
不幸的是,我发现编译器之间存在不一致。使用GCC 7.1和Visual Studio 2015U3编译时,此代码(添加了用于比较的boost实现)会产生不同的结果:
select
doctor0_.doctorId as doctorId1_3_0_,
timetables1_.timeTableId as timeTabl1_5_1_,
doctor0_.address as address2_3_0_,
doctor0_.branch as branch3_3_0_,
doctor0_.contactNo as contactN4_3_0_,
doctor0_.designation as designat5_3_0_,
doctor0_.email as email6_3_0_,
doctor0_.fullName as fullName7_3_0_,
doctor0_.password as password8_3_0_,
doctor0_.regNo as regNo9_3_0_,
doctor0_.speciality as special10_3_0_,
doctor0_.workingTime as working11_3_0_,
timetables1_.date as date2_5_1_,
timetables1_.doctorId as doctorId5_5_1_,
timetables1_.hospital as hospital3_5_1_,
timetables1_.time as time4_5_1_
from
Doctor doctor0_
inner join
TimeTable timetables1_
on doctor0_.doctorId=timetables1_.doctorId
where
doctor0_.fullName='Subash Nisam'
and timetables1_.date='2017.03.02'
GCC
#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';
}
MSVC:
123\\.456\\^789\\$123\\\456\\|789\\*123\\+456\\(789\\)123\\?456
123\.456\^789\$123\\456\|789\*123\+456\(789\)123\?456
这是预期的行为吗?
答案 0 :(得分:1)
您要求将正则表达式引擎替换为R"(\\\1&)"
,\\\1&
替换模式将其视为sed
replacement pattern。在sed中,&
代表整场比赛。由于模式中没有ID为1的组,\1
引用空字符串。当使用std::regex_replace
进行解析时,前两个反斜杠是原始字符串文字中的2个字面反斜杠。
使用Boost时,前两个反斜杠被解析为单个反斜杠,必须转义Boost替换模式中的文字反斜杠才能使用单个文字反斜杠作为替换:
Sed样式格式字符串将所有字符视为文字除外:
&
&符号在输出流中被与正则表达式匹配的全部内容替换。使用\&amp;输出文字&#39;&amp;&#39;字符。
\
指定转义序列。
关于替换模式的其余部分,它将起作用。
您可以使用
std::regex_replace(s, std::regex{ R"(([.^$|{}()[\]*+?/\\]))" }, std::string{ R"(\$1)" }, std::regex_constants::match_default);
使用Boost,可以使用等效的方法/选项来实现结果的一致性。在这里,使用默认引擎。
关于MSVC和GCC的差异,关于这一点的文档很少。很明显,在两个提到的编译器之间定义文字反斜杠行为是不同的。请注意,许多正则表达式库将文字反斜杠视为正则表达式转义(与Boost相同,请参见上面的参考),并且要定义文字替换反斜杠,您需要在替换模式中加倍文字反斜杠。您在GCC中使用的引擎是ECMAScript。
似乎应该如何定义反向间隙替换模式留给每个正则表达式替换实现。当您将其与GCC一起使用时,单个文字\
(= "\\"
)将被视为单个文字替换反斜杠。 MSVC编译器决定使用大多数正则表达式引擎 - 这是有道理的,因为在使用\1
时可以使用替换后向引用\9
- std::regex_constants::format_sed
- 需要使用文字替换反斜杠转义并使用单个\
替换,您需要使用两个文字反斜杠,"\\\\"
(或R"(\\)"
)。