Boost Spirit Qi为何未抛出expectation_failure且存在未解析内容?
Boost Spirit Qi解析问题解决方案
问题1:强制校验输入以标识符开头并抛出期望失败异常
要实现输入必须以标识符开头且抛出qi::expectation_failure,需做两点修改:
- 使用
qi::expect包裹标识符规则,强制要求匹配成功,否则直接抛出异常 - 加上
qi::eoi确保整个输入被完全解析,避免残留未解析内容
示例规则修改:
// 原规则 // rule = identifier >> ':' >> value; // 修改后规则 rule = qi::expect[identifier] > ':' > value > qi::eoi;
- 空字符串或数字开头的输入会触发
identifier匹配失败,expect直接抛出qi::expectation_failure qi::eoi确保输入无剩余内容,避免解析部分成功但存在未解析数据的情况
问题2:优化错误提示精准度
解析a$时仅提示预期:,是因为标识符a匹配成功,后续规则期望:但遇到$。要让错误提示关联规则名称,需:
- 给每个规则调用
name()方法命名 - 启用
qi::on_error自定义错误输出逻辑
示例代码片段:
// 给规则命名 qi::rule<Iterator, std::string()> identifier; identifier %= qi::alpha >> *qi::alnum; identifier.name("identifier"); qi::rule<Iterator, std::string()> value; value %= +qi::char_("a-zA-Z0-9"); value.name("value"); // 主规则 qi::rule<Iterator, std::pair<std::string, std::string>()> start; start = qi::expect[identifier] > ':' > value > qi::eoi; start.name("key-value pair"); // 自定义错误输出 qi::on_error<qi::fail>(start, [](const auto& ctx) { size_t pos = qi::_where(ctx) - qi::_begin(ctx); std::cout << "Error at position " << pos << ": "; std::cout << "Expected '" << qi::_what(ctx) << "', got '"; if (qi::_where(ctx) != qi::_end(ctx)) std::cout << *qi::_where(ctx); else std::cout << "end of input"; std::cout << "'\n"; });
- 解析
a$时,会提示"Expected ':', got '$'" - 解析
23434时,会提示"Expected 'identifier', got '2'"
完整可运行示例
#include <boost/spirit/include/qi.hpp> #include <iostream> #include <string> #include <utility> namespace qi = boost::spirit::qi; template <typename Iterator> struct KeyValueParser : qi::grammar<Iterator, std::pair<std::string, std::string>()> { KeyValueParser() : KeyValueParser::base_type(start) { // 定义标识符规则并命名 identifier %= qi::alpha >> *qi::alnum; identifier.name("identifier"); // 定义值规则并命名 value %= +qi::char_("a-zA-Z0-9"); value.name("value"); // 主规则:强制标识符开头,必须匹配完整输入 start = qi::expect[identifier] > ':' > value > qi::eoi; start.name("key-value pair"); // 自定义错误处理逻辑 qi::on_error<qi::fail>(start, [](const auto& ctx) { size_t pos = qi::_where(ctx) - qi::_begin(ctx); std::cout << "Error at position " << pos << ": "; std::cout << "Expected '" << qi::_what(ctx) << "', got '"; if (qi::_where(ctx) != qi::_end(ctx)) std::cout << *qi::_where(ctx); else std::cout << "end of input"; std::cout << "'\n"; }); } qi::rule<Iterator, std::string()> identifier, value; qi::rule<Iterator, std::pair<std::string, std::string>()> start; }; int main() { using Iterator = std::string::const_iterator; KeyValueParser<Iterator> parser; // 测试用例1:数字开头输入 std::cout << "Test 1: '23434'\n"; std::string input1 = "23434"; Iterator it1 = input1.begin(), end1 = input1.end(); try { std::pair<std::string, std::string> result1; bool ok = qi::parse(it1, end1, parser, result1); if (!ok || it1 != end1) { throw qi::expectation_failure<Iterator>(it1, "complete input"); } } catch (const qi::expectation_failure<Iterator>& e) { std::cout << "Expectation failure: Expected '" << e.what() << "'\n"; } // 测试用例2:空字符串 std::cout << "\nTest 2: ''\n"; std::string input2 = ""; Iterator it2 = input2.begin(), end2 = input2.end(); try { std::pair<std::string, std::string> result2; bool ok = qi::parse(it2, end2, parser, result2); if (!ok || it2 != end2) { throw qi::expectation_failure<Iterator>(it2, "complete input"); } } catch (const qi::expectation_failure<Iterator>& e) { std::cout << "Expectation failure: Expected '" << e.what() << "'\n"; } // 测试用例3:a$ std::cout << "\nTest 3: 'a$'\n"; std::string input3 = "a$"; Iterator it3 = input3.begin(), end3 = input3.end(); try { std::pair<std::string, std::string> result3; bool ok = qi::parse(it3, end3, parser, result3); if (!ok || it3 != end3) { throw qi::expectation_failure<Iterator>(it3, "complete input"); } } catch (const qi::expectation_failure<Iterator>& e) { std::cout << "Expectation failure: Expected '" << e.what() << "'\n"; } return 0; }
内容的提问来源于stack exchange,提问作者llm
相关产品推荐
相关产品推荐

