You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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匹配成功,后续规则期望:但遇到$。要让错误提示关联规则名称,需:

  1. 给每个规则调用name()方法命名
  2. 启用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 10:23:26