c++ - boost spirit 解析器前瞻解析

标签 c++ parsing c++11 boost boost-spirit

我想解析一个字符串,它的形式是: 字符串编号。 我不确定如何为 boost qi 解析器编写语法。

现在我的语法是这样的: +qi::char_("a-zA-Z0-9_-") >> lit('<code>_</code>') >> qi::int_

但是看起来好像不行。 示例字符串是: ab_bcd_123 --> token (ab_bcd, 123) ab_123 ---> token (ab, 123)

最佳答案

But doesn't look like it works.

那是因为 0-9 吃掉了数字。这应该有效:

+qi::char_("a-zA-Z_") >> '_' >> qi::uint_

如果您也想允许 ab-3_bcd_123,请使用前瞻性设备来检测您是否已到达终点,例如eoi:

qi::raw[
    (+qi::alnum|'-') % (!('_' >> qi::uint_ >> eoi))
] >> '_' >> qi::uint_

虽然到现在为止,我只是忘记它并做:

qi::lexeme [ +qi::char_("a-zA-Z0-9_-") ] [ _val = split_ident(_1) ];

参见 Live On Coliru

#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi = boost::spirit::qi;

using NumberedIdent = std::pair<std::string, int>;

namespace Demo {
    struct SplitIdent {
        NumberedIdent operator()(std::vector<char> const& v, bool& pass) const {
            std::string s(v.begin(), v.end());
            try {
                auto n = s.rfind('_');
                pass = n > 0;
                return { s.substr(0, n), std::stoi(s.substr(n+1)) };
            } catch(...) { 
                pass = false; return {s, 0}; 
            }
        }
    };

    using It = std::string::const_iterator;
    using namespace qi;

    static boost::phoenix::function<SplitIdent> split_ident;

    rule<It, NumberedIdent()> const rule
        = lexeme [ +char_("a-zA-Z0-9_-") ] [ _val = split_ident(_1, _pass) ];
}

int main() {
    for (std::string const input : {
           "ab_bcd_123",
           "ab-3_bcd_123 = 'something'",
           // failing:
           "ab_bcd_123_q = 'oops'",
           "ab_bcd_123_ = 'oops'",
           "_123 = 'oops'",
           "_",
           "q",
           ""
           }) 
    {
        NumberedIdent parsed;
        Demo::It f = input.begin(), l = input.end();

        bool ok = parse(f, l, Demo::rule, parsed);

        if (ok) {
            std::cout << "SUCCESS: ['" << parsed.first << "', " << parsed.second << "]\n";
        } else {
            std::cout << "parse failed ('" << input << "')\n";
        }

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

}

打印:

SUCCESS: ['ab_bcd', 123]
SUCCESS: ['ab-3_bcd', 123]
  remaining input ' = 'something''

然后是所有失败的测试用例(按设计):

parse failed ('ab_bcd_123_q = 'oops'')
  remaining input 'ab_bcd_123_q = 'oops''
parse failed ('ab_bcd_123_ = 'oops'')
  remaining input 'ab_bcd_123_ = 'oops''
parse failed ('_123 = 'oops'')
  remaining input '_123 = 'oops''
parse failed ('_')
  remaining input '_'
parse failed ('q')
  remaining input 'q'
parse failed ('')

关于c++ - boost spirit 解析器前瞻解析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44169514/

相关文章:

c# - 用引号解析命令行参数

c++ - 如何在C++中将多个文件包装到同一个命名空间中

c++ - Eigen3根据列条件选择行

c++ - iOS - Xcode - OpenCV - findContours 错误

c - 解析读入文件并将其存储在二叉树中

python - 基于 pyparsing 的分割

c++ - 字节顺序标记真的是一个有效的标识符吗?

c++ - Braced-init-lists 和函数模板类型推导顺序

c++ - 将 bool 转换为位域中的位

c++ - 使用 regex_* 解析/etc/passwd,非标准行为 C++