【问题标题】:boost::spirit: how to write a parser that parses 2 strings and have them 'combined' into only one?boost::spirit: 如何编写解析 2 个字符串并将它们“组合”成一个的解析器?
【发布时间】:2014-10-26 09:30:29
【问题描述】:

我有一个 qi::symbol<char, std::string> escapedDoubleQuote 可以将双精度 "" 转换为 \"

我尝试将其用于更复杂的解析器,并希望结果仍然是单个字符串。但没有成功。我试过有无qi::lexemeqi::as_stringqi::as<std::string>

#include <iostream>
#include <boost/spirit/home/qi.hpp>
#include <vector>
#include <string>

namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

struct escapedDoubleQuote_ : qi::symbols<char, std::string >
{
    escapedDoubleQuote_()
    {
        add("\"\"", "\\\"");
    }
} escapedDoubleQuote;

template<typename Iterator>
struct MyGrammar : qi::grammar<Iterator, std::string()>
{
    MyGrammar() : MyGrammar::base_type(escapedField)
    {
        subField = +(~qi::char_("\""));
        escapedField =
                qi::lexeme[  // or qi::as<std::string> ... both seems to do nothing.
                    subField
                    >> -(escapedDoubleQuote >> escapedField)
                ];
    }

    qi::rule<Iterator, std::string()> subField;
    qi::rule<Iterator, std::string()> escapedField;
};

int main()
{
    typedef std::string::const_iterator iterator_type;
    typedef MyGrammar<iterator_type> parser_type;
    parser_type parser;

    std::string input = "123\"\"456\"\"789";
    std::string output;
    iterator_type it = input.begin();
    bool parsed = parse(
            it,
            input.cend(),
            parser,
            output
    );

    if(parsed && it == input.end())
    {
        std::cout << output << std::endl;
        // expected: 123\"456\"789
        // actual  : \"789
    }

    return 0;
}

最后,我想使用解析器并输出一个std::string。在示例中123\"\"456\"\"789 应该输出123\"456\"789


注意:我知道我可以将escapedDoubleQuote 定义为qi::symbols&lt;char, std::vector&lt;char&gt; &gt; 以便实现结果,但我想了解是否以及如何组合字符串。

【问题讨论】:

  • 当你“从一个值分配给一个容器”并且容器和值都是相同的类型时,Spirit会用值覆盖容器(参见“boost/spirit/home/qi/detail /assign_to.hpp" 搜索 struct assign_to_container_from_value&lt;Attribute, Attribute&gt;)。如果您在symbols 中使用vector&lt;char&gt;,则类型不一样,并且选择到达void append_to_string(Attribute&amp; attr, Iterator begin, Iterator end) 的另一条路径符合您的预期。 This hack 回避了这个问题,但可能会破坏其他东西。
  • @cv_and_he 是的,这看起来太老套了。我个人不会触及内置类型的特征。虽然 /cc OP 包含在包含的好地方:请注意!

标签: c++ boost boost-spirit


【解决方案1】:

正如@cv_and_he 所建议的,“原子”赋值行为源于暴露的属性类型 (std::vector&lt;char&gt;) 到 std::string 的转换。

具体来说就是escapedField的声明属性,因为递归调用的时候会创建不兼容的综合属性组合:[std::vector&lt;char&gt;, std::string, std::string]

如果您可以保持属性“相等”,则可以解决问题:

MyGrammar() : MyGrammar::base_type(start)
{
    subField     = +(~qi::char_("\""));
    escapedField = subField >> -(escapedDoubleQuote >> escapedField);
    start        = escapedField;
}

qi::rule<Iterator, std::vector<char>()> subField, escapedField;
qi::rule<Iterator, std::string()> start;

Live On Coliru

(我删除了lexeme,因为您在示例代码中没有跳过,请参阅Boost spirit skipper issues

【讨论】:

  • 请注意,如果您将symbols 的属性设为vector&lt;char&gt; it does not work again。因此,它仅在每个连接中的属性不同时才有效(在您的情况下,您有vector&lt;char&gt;stringvector&lt;char&gt; 的结果连接,即string)。我认为这是一个错误,但我真的不确定,可能在另一个用例中需要它。
  • @cv_and_he 哦。你说得很对。那是……烦人。我会把它留给 OP 他是否想在 [spirit-general] 邮件列表中报告。
  • hm,所以还没有真正的解决方案吗?我不明白 boost::spirit 的内部原理,不足以说它是一个错误或预期的行为。
  • 我会说这是缺乏预期的功能。可以预期,因为类似的解析器表达式群(与规则或转换的子属性相反)确实按预期工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-25
  • 2021-10-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多