【问题标题】:Spirit QI parser end eomSpirit QI 解析器 end eom
【发布时间】:2020-05-07 15:00:24
【问题描述】:

我的数据定义为:

std::string data("START34*23*43**");

我的语法:

"START" >> boost::spirit::hex % '*'

问题: 如何解析有两颗星的消息结尾?

https://wandbox.org/permlink/oDYjbBDb8fy79zQV

【问题讨论】:

  • 你想要发生什么? 2星是什么意思?无论如何,一颗星是什么意思?
  • 两颗星表示结束消息。所以我们已经开始了。有效载荷(数据)由星号分隔,并结束消息标记(两个星号)。所以基本上我只想接受“START34*23*43**”并拒绝其他所有内容
  • @sehe 所以有点像这样:coliru.stacked-crooked.com/a/5ecc5462a8dc0081
  • 这就是好好提问的艺术!我用 UPDATE 扩展了我的答案。

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


【解决方案1】:

目前还不清楚你在问什么。假设您只想“忽略”(或接受)尾随星号,这就是您的罪魁祸首:

if (first != last) // fail if we did not get a full match
    return false;

只需删除这些行就可以了:

Live On Coliru(注意大大简化了):

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

namespace qi = boost::spirit::qi;

template <typename Iterator>
bool parse_numbers(Iterator& first, Iterator last, std::vector<unsigned>& v) {
    return qi::phrase_parse(first, last, ("START" >> qi::hex % '*'), qi::space, v);
}

int main() {
    for (std::string const data : {
             "START34*23*43",
             "START34 * 23 * 43",
             "START34 * 23 * 43 *",
             "START34 * 23 * 43**",
             "START34 * 23 * 43* *",
         })
    {
        auto f = data.begin(), l = data.end();
        std::vector<unsigned> v;

        if (parse_numbers(f, l, v)) {
            std::cout << std::quoted(data) << " Parses OK: " << std::endl;

            for (auto i = 0u; i < v.size(); ++i)
                std::cout << i << ": " << v[i] << std::endl;
        } else {
            std::cout << "Parsing failed\n";
        }
        if (f != l) {
            std::cout << "Remaining unparsed: "
                      << std::quoted(std::string(f, l)) << "\n";
        }
    }
}

打印

"START34*23*43" Parses OK: 
0: 52
1: 35
2: 67
"START34 * 23 * 43" Parses OK: 
0: 52
1: 35
2: 67
"START34 * 23 * 43 *" Parses OK: 
0: 52
1: 35
2: 67
Remaining unparsed: "*"
"START34 * 23 * 43**" Parses OK: 
0: 52
1: 35
2: 67
Remaining unparsed: "**"
"START34 * 23 * 43* *" Parses OK: 
0: 52
1: 35
2: 67
Remaining unparsed: "* *"

或者

如果您确实想忽略相邻的 ** 但仍继续解析,那么有用的更改是说 -qi::hex % '*' 而不是 qi::hex % '*' 这只是使 hex 可选。

Live On Coliru

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

namespace qi = boost::spirit::qi;

template <typename Iterator>
bool parse_numbers(Iterator& first, Iterator last, std::vector<unsigned>& v) {
    return qi::phrase_parse(first, last,
            ("START" >> -qi::hex % '*'), qi::space, v);
}

int main() {
    for (std::string const data : {
             "START34**23*43",
             "START34 * 23 * 43**",
             "START*******",
             "START*******1 BOGUS",
         })
    {
        auto f = data.begin(), l = data.end();
        std::vector<unsigned> v;

        if (parse_numbers(f, l, v)) {
            std::cout << std::quoted(data) << " Parses OK: " << std::endl;

            for (auto i = 0u; i < v.size(); ++i)
                std::cout << i << ": " << v[i] << std::endl;
        } else {
            std::cout << "Parsing failed\n";
        }
        if (f != l) {
            std::cout << "Remaining unparsed: "
                      << std::quoted(std::string(f, l)) << "\n";
        }
    }
}

打印

"START34**23*43" Parses OK: 
0: 52
1: 35
2: 67
"START34 * 23 * 43**" Parses OK: 
0: 52
1: 35
2: 67
"START*******" Parses OK: 
"START*******1 BOGUS" Parses OK: 
0: 1
Remaining unparsed: "BOGUS"

在这种情况下,您可能需要重新断言所有输入都使用 &gt;&gt; qi::eoi 解析(这优于手动检查迭代器),请参阅 Live On Coliru

"START34**23*43" OK: 
0: 52
1: 35
2: 67
"START34 * 23 * 43**" OK: 
0: 52
1: 35
2: 67
"START*******" OK: 
"START*******1 BOGUS" Failed

更新

到您comment 中的更新问题:

@sehe 就像这样:coliru.stacked-crooked.com/a/5ecc5462a8dc0081 – user3314011 19 mins ago

您需要负前瞻来排除**

"START" >> (qi::hex % (qi::lit('*') - "**")) >> "**"

其实,让我们添加一些期望点(&gt; 而不是&gt;&gt;):

    try {
        return qi::parse(first, last, "START" > (qi::hex % (qi::lit('*') - "**")) > "**" > qi::eoi, v);
    } catch (qi::expectation_failure<Iterator> const& ef) {
        std::ostringstream msg;
        msg << "Expected " << ef.what_ << " at " << std::quoted(std::string(ef.first, ef.last), '\'');
        throw ParseError(msg.str());
    }

现在你也可以得到一些不错的错误信息了:

Live On Coliru

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

namespace qi = boost::spirit::qi;

struct ParseError : std::runtime_error {
    ParseError(std::string msg) : std::runtime_error(std::move(msg)) {}
};

template <typename Iterator>
bool parse_numbers(Iterator& first, Iterator last, std::vector<unsigned>& v) {
    try {
        return qi::parse(first, last, "START" > (qi::hex % (qi::lit('*') - "**")) > "**" > qi::eoi, v);
    } catch (qi::expectation_failure<Iterator> const& ef) {
        std::ostringstream msg;
        msg << "Expected " << ef.what_ << " at " << std::quoted(std::string(ef.first, ef.last), '\'');
        throw ParseError(msg.str());
    }
}

int main() {
    for (std::string const data : {
             "START34*23*43",       // Fail no EOM
             "START34 * 23 * 43",   // Fail spaces
             "START34*23*43*",      // Fail no EOM
             "START34*23*43**",     // OK
             "START34*23*43**1",    // Fail extra number
         })
    {
        std::cout << std::quoted(data) << " -> ";

        auto f = data.begin(), l = data.end();
        std::vector<unsigned> v;

        try {
            if (parse_numbers(f, l, v)) {
                std::cout << " OK:";

                for (auto i : v)
                    std::cout << " " << i;
                std::cout << "\n";
            } else {
                std::cout << "Not matched\n";
            }
        } catch(ParseError const& pe) {
            std::cout << "Error: " << pe.what() << "\n";
        }
    }
}

印刷:

"START34*23*43" -> Error: Expected "**" at ''
"START34 * 23 * 43" -> Error: Expected "**" at ' * 23 * 43'
"START34*23*43*" -> Error: Expected "**" at '*'
"START34*23*43**" ->  OK: 52 35 67
"START34*23*43**1" -> Error: Expected <eoi> at '1'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-01
    • 1970-01-01
    • 2016-10-06
    • 1970-01-01
    相关资源
    最近更新 更多