使用Boost Spirit Qi解析分隔的令牌列表

时间:2014-10-24 13:07:39

标签: c++ parsing boost boost-spirit-qi

使用boost :: spirit :: qi我尝试解析由标签后跟可变数量的分隔标记组成的行。我使用 phrase_parse 调用语法,并使用提供的空白解析器作为跳过解析器来保留换行符,因为我需要确保标签是每个标签上的第一个项目线。

简单的基本情况:

label token, token, token

可以用语法解析:

line = label >> (token % ',') >> eol;

我面临的问题是语法应该接受零个或多个令牌,并且令牌可能是空的。语法应该接受以下几行:

label
label ,
label , token
label token, , token,

我还没有设法创建一个接受上述所有示例的语法。 关于如何解决这个问题的任何建议?

修改

感谢关于上述问题的所有输入。 现在,我忘了包括有趣的部分...... 语法也应该接受空行和分割线。 (没有标签的代币) 当我尝试使标签可选时,我得到一个与空字符串匹配的无限循环。

label

label token
token

1 个答案:

答案 0 :(得分:3)

你应该能够接受带有

的空列表
line = label >> -(token % ',') >> eol;

请注意,eol如果你的队长也跳过了eol也不会工作(所以不要使用qi::space但是qi::blank用于此目的)

此外,根据token的定义,你应该改变它以接受"空"令牌以及


回应评论:完整的工作示例 Live On Coliru

#include <boost/spirit/include/qi.hpp>

namespace qi = boost::spirit::qi;

int main()
{
    using namespace qi;

    using It     = std::string::const_iterator;
    using Token  = std::string;
    using Tokens = std::vector<Token>;

    rule<It, blank_type> label 
        = lexeme[+~char_(":")] >> ':'
        ;

    rule<It, Token(), blank_type> token
        = lexeme[*~char_(",\n")];
        ;

    rule<It, Tokens(), blank_type> line
        = label >> -(token % ',') >> eol
        ;

    for (std::string const input : {
        "my first label: 123, 234, 345 with spaces\n",
        "1:\n",
        "2: \n",
        "3: ,,,\n",
        "4: ,  \t ,,\n",
        "5: ,  \t , something something,\n",
    })
    {
        std::cout << std::string(40, '=') << "\nparsing: '" << input << "'\n";

        Tokens parsed;
        auto f = input.begin(), l = input.end();
        bool ok = phrase_parse(f, l, line, blank, parsed);

        if (ok)
        {
            std::cout << "Tokens parsed successfully, number parsed: " << parsed.size() << "\n";
            for (auto token : parsed)
                std::cout << "token value '" << token << "'\n";
        }
        else
            std::cout << "Parse failed\n";

        if (f != l)
            std::cout << "Remaining input: '" << std::string(f, l) << "'\n";
    }
}

输出:

========================================
parsing: 'my first label: 123, 234, 345 with spaces
'
Tokens parsed successfully, number parsed: 3
token value '123'
token value '234'
token value '345 with spaces'
========================================
parsing: '1:
'
Tokens parsed successfully, number parsed: 1
token value ''
========================================
parsing: '2: 
'
Tokens parsed successfully, number parsed: 1
token value ''
========================================
parsing: '3: ,,,
'
Tokens parsed successfully, number parsed: 4
token value ''
token value ''
token value ''
token value ''
========================================
parsing: '4: ,       ,,
'
Tokens parsed successfully, number parsed: 4
token value ''
token value ''
token value ''
token value ''
========================================
parsing: '5: ,       , something something,
'
Tokens parsed successfully, number parsed: 4
token value ''
token value ''
token value 'something something'
token value ''