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

Parsing delimited list of tokens using Boost Spirit Qi

本文关键字:分隔 令牌 列表 Boost Spirit Qi 使用      更新时间:2023-10-16

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

简单的基本情况:

label token, token, token

可以用语法进行解析:

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

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

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

我还没有创建一个可以接受上面所有示例的语法。关于如何解决这个问题,有什么建议吗?

编辑:

感谢sehe对上述问题的所有投入。现在我忘了把有趣的部分包括在内。。。语法还应该接受空行和拆分行。(没有标签的令牌)当我试图使标签可选时,我会得到一个与空字符串匹配的无限循环。

label
label token
token

您应该能够接受的空列表

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

请注意,如果您的船长也跳过eol,eol将不起作用(因此不要使用qi::space,但例如qi::blank

此外,根据token的定义,您可能应该将其更改为接受"空"令牌以及


针对评论:一个完整的工作样本在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 spacesn",
        "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 failedn";
        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 ''