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

使用Boost Spirit Qi解析含空白的标识符串并映射到结构体

问题解决:Boost Spirit Qi 解析时空白符混入结果的问题

问题原因

你的猜想完全正确——*qi::space和+qi::space会生成对应属性(匹配到的空白符序列),当这些规则和返回std::string的identifier_rule通过>>连接时,Spirit会把所有规则的属性按顺序组合成一个属性序列。而abc_rule要适配Out结构体(需要3个std::string属性),所以Spirit会错误地将前三个属性(开头的空白符、第一个标识符、中间的空白符)分别赋值给a、b、c,直接导致断言失败。

两种可行解决方案

方案1:用qi::omit屏蔽空白符的属性

直接把空白符规则包裹在qi::omit[]中,让它们不生成属性,这样最终的属性序列就只剩下三个标识符的结果:

boost::spirit::qi::rule<char const*, Out()> abc_rule =
    qi::omit[*qi::space] >> identifier_rule 
    >> qi::omit[+qi::space] >> identifier_rule 
    >> qi::omit[+qi::space] >> identifier_rule 
    >> qi::omit[*qi::space];

方案2:使用Spirit的自动空白跳过(更简洁)

Spirit支持为规则设置跳过器,自动忽略指定的空白符,这样你不需要手动写空白符规则,代码会简洁很多:

// 为规则设置自动跳过空白符的特性
qi::rule<char const*, std::string(), qi::space_type> identifier_rule = 
    qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z0-9_");

boost::spirit::qi::rule<char const*, Out(), qi::space_type> abc_rule =
    identifier_rule >> identifier_rule >> identifier_rule;

// 解析时用phrase_parse指定跳过器为qi::space
assert(qi::phrase_parse(f, l, abc_rule, qi::space, o));

这里phrase_parse会自动应用qi::space作为跳过器,忽略所有空白符(包括空格、换行、制表符等),你只需要定义核心的标识符序列规则即可。

修改后的完整代码(以方案2为例)

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

namespace qi = boost::spirit::qi;

struct Out
{
    Out() = default;
    Out(const std::string& a_, const std::string& b_, const std::string& c_) : 
        a(a_), b(b_), c(c_)
    {}
    std::string a;
    std::string b;
    std::string c;
};
BOOST_FUSION_ADAPT_STRUCT(Out, a, b, c)

int main()
{
    qi::rule<char const*, std::string(), qi::space_type> identifier_rule = 
        qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z0-9_");

    boost::spirit::qi::rule<char const*, Out(), qi::space_type> abc_rule =
        identifier_rule >> identifier_rule >> identifier_rule;

    // 测试三种输入场景
    std::string tests[] = {
        "blub blib blab",
        "\n  \n blub \t \t \n blib  \t \n  blab \n \t \n",
        "  blub   blib  blab  "
    };

    for (auto& test : tests) {
        Out o;
        char const* f(test.c_str());
        char const* l(f + test.size());
        assert(qi::phrase_parse(f, l, abc_rule, qi::space, o));
        assert(o.a == "blub");
        assert(o.b == "blib");
        assert(o.c == "blab");
    }
    
    return 0;
}

补充说明

  • 方案2更符合Spirit的设计理念,尤其是解析脚本语言时,自动空白跳过能大幅简化规则定义,避免手动处理各种空白场景。
  • 如果后续需要保留某些空白符(比如字符串内部的空格),可以在对应规则中用qi::lexeme[]包裹,临时禁用跳过器,这是解析复杂语法时常用的技巧。

内容的提问来源于stack exchange,提问作者llm

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 16:22:38