问题描述
下面的解析器处理诸如“a \"quoted\" string”之类的字符串,但去掉转义的引号,留下“一个带引号的字符串”。为什么?是否有可能阻止它这样做,或者是 this 唯一的方法?
template <typename IteratorT,typename SkipperT>
struct quoted_string_grammar
: qi::grammar<IteratorT,std::string(),SkipperT >
{
quoted_string_grammar()
: quoted_string_grammar::base_type(rule,"String")
{
using namespace qi;
rule %= lexeme [
lit(L'"')
>> *(lit("\\\"") | (char_ - char_('"')))
> lit('"')
];
}
qi::rule<IteratorT,SkipperT> rule;
};
\
解决方法
原则上,您希望在解析过程中解释转义。
非常罕见的例外情况包括您打算“仅验证”并转发相同的输入。但是,如果是这种情况,那么您将不需要 任何 属性(这在 Spirit 中很简单:不要传递一个)。
此外,这是一种安全气味,因为您可能永远不应该相信您的输入。
还有一个奇怪的地方:
- 你有一个带船长的语法,然后唯一的规则是完全词素(见Boost spirit skipper issues)。
- 你处理
\"
但\
没有任何神奇的意义。这令人困惑。 - 您有多余的
lit()
包装字符文字 -
char_ - char_('"')
可以(应该?)更有效地写成~char_('"')
- 有一个杂散的宽字符文字
解决所有这些问题,我会把整个事情写成
qi::rule<Iterator,std::string()> rule;
rule = '"' >> *~char_('"') >> '"';
如果有转义,我会写
rule = '"' >> *('\\' >> char_ | ~char_('"')) >> '"';
暴露原始输入:
rule = raw['"' >> *('\\' >> char_ | ~char_('"')) >> '"'];
你可以删除整个语法结构。
说明性演示
没有现场演示,答案是不完整的。它特别强调了上面提到的一些奇怪之处。
#include <boost/spirit/include/qi.hpp>
#include <iomanip>
namespace qi = boost::spirit::qi;
std::string parse(std::string const& input) {
std::string result;
static const qi::rule<std::string::const_iterator,std::string()> rule
= '"' >> *('\\' >> qi::char_ | ~qi::char_('"')) >> '"';
// throws if expectation failures
qi::parse(input.begin(),input.end(),qi::eps > rule > qi::eoi,result);
return result;
}
int main() {
auto sq = [](auto s) { return std::quoted(s,'\''); };
auto dq = [](auto s) { return std::quoted(s,'"'); };
for (std::string s : {
R"("")",R"("hello")",R"("hello \"world\"! ")",R"("hello \'world\'! ")",}) {
std::cout << s << " -> " << parse(s) << "\n";
std::cout << sq(s) << " -> " << sq(parse(s)) << "\n";
std::cout << dq(s) << " -> " << dq(parse(s)) << "\n";
std::cout << "----\n";
}
}
印刷品
"" ->
'""' -> ''
"\"\"" -> ""
----
"hello" -> hello
'"hello"' -> 'hello'
"\"hello\"" -> "hello"
----
"hello \"world\"! " -> hello "world"!
'"hello \\"world\\"! "' -> 'hello "world"! '
"\"hello \\\"world\\\"! \"" -> "hello \"world\"! "
----
"hello \'world\'! " -> hello 'world'!
'"hello \\\'world\\\'! "' -> 'hello \'world\'! '
"\"hello \\'world\\'! \"" -> "hello 'world'! "
----
我希望这是一个 Zen Koan。公案结束:
弟子对代码的输出进行了 37 天的冥想,然后他开悟了。