如何解析包含带有增强精神的嵌入引号的带引号的字符串

问题描述

下面的解析器处理诸如“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_('"')) >> '"'];

你可以删除整个语法结构。

说明性演示

没有现场演示,答案是不完整的。它特别强调了上面提到的一些奇怪之处。

Live On Coliru

#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 天的冥想,然后他开悟了。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...