boost :: spirit:如何编写一个解析器来解析2个字符串并将它们组合起来'只进一个?

时间:2014-10-26 09:30:30

标签: c++ boost boost-spirit

我有一个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<char, std::vector<char> >,以便实现结果,但我想了解是否以及如何组合字符串。

1 个答案:

答案 0 :(得分:0)

正如@cv_and_he所建议的那样,“原子”赋值行为源于公开属性类型(std::vector<char>)到std::string的转换。

具体来说,它是关于escapedField的声明属性,因为当它以递归方式调用时,会创建不兼容的合成属性组合:[std::vector<char>, 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