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

使用Boost.Spirit解析INI段失败,请求排查问题

Boost.Spirit INI解析器失败问题排查与解决

问题背景

正在为大学项目学习解析器,选用Boost.Spirit库。完成基础示例实现后,尝试编写小型INI段解析器,但程序解析失败。

错误输出

<section>
  <try>[Section]\nkey1 = val</try>
  <key>
    <try>Section]\nkey1 = valu</try>
    <success>]\nkey1 = value1\nkey2</success>
    <attributes>[]</attributes>
  </key>
  <fail/>
</section>

--------------------
Parsing failed
--------------------

相关代码

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

#include <iostream>
#include <string>

using namespace std;

namespace client 
{
    namespace qi    = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;
    
    template <typename Iterator>
    struct ini_grammar : qi::grammar<Iterator, ascii::space_type>
    {
        ini_grammar() : ini_grammar::base_type(section)
        {
            using qi::char_;
           
            key     = +char_("a-zA-Z_0-9");
            pair    = key >> '=' >> key;
            section =
                '[' >> key  >> ']' 
                >> '\n'
                >> *(pair >> '\n')
                ;
            BOOST_SPIRIT_DEBUG_NODES((key)(pair)(section))
        }

            qi::rule<Iterator, ascii::space_type> section, pair, key;
    };
}


int main() 
{
    using boost::spirit::qi::phrase_parse;
    using boost::spirit::ascii::space;

    string ini_section =
        "[Section]\n"
        "key1 = value1\n"
        "key2 = value2\n";

    typedef client::ini_grammar<string::const_iterator> ini_grammar;
    ini_grammar grammar;
    
    string::const_iterator iter = ini_section.begin();
    string::const_iterator end  = ini_section.end();

    bool r = phrase_parse(iter, end, grammar, space);

    if (r == true) 
    {
        cout << "-------------------------\n";
        cout << "Parsing succeeded\n";
        cout << "-------------------------\n";
    }

    else 
    {
        cout << "-------------------------\n";
        cout << "Parsing failed\n";
        cout << "-------------------------\n";
    }
    return 0;
}

问题原因分析

  1. 空格处理冲突:phrase_parse使用的ascii::space skipper会自动跳过所有空白字符(包括换行),但代码中显式写了>> '\n'要求匹配换行符,此时换行已被skipper吃掉,导致匹配失败。
  2. 规则属性缺失:所有规则未定义属性类型,解析器无法捕获匹配结果,调试输出中<attributes>[]也证明了这一点,属性缺失会影响解析逻辑的正确性。

解决方法

修改后的完整代码

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

#include <iostream>
#include <string>
#include <vector>
#include <utility>

using namespace std;

namespace client 
{
    namespace qi    = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;
    
    template <typename Iterator>
    struct ini_grammar : qi::grammar<Iterator, pair<string, vector<pair<string, string>>>, ascii::blank_type>
    {
        ini_grammar() : ini_grammar::base_type(section)
        {
            using qi::char_;
            using qi::eol;
           
            key     = +char_("a-zA-Z_0-9");
            pair    = key >> '=' >> key;
            section =
                '[' >> key >> ']' 
                >> eol
                >> *(pair >> eol)
                ;
            BOOST_SPIRIT_DEBUG_NODES((key)(pair)(section))
        }

        qi::rule<Iterator, string(), ascii::blank_type> key;
        qi::rule<Iterator, pair<string, string>(), ascii::blank_type> pair;
        qi::rule<Iterator, pair<string, vector<pair<string, string>>>, ascii::blank_type> section;
    };
}


int main() 
{
    using boost::spirit::qi::phrase_parse;
    using boost::spirit::ascii::blank;

    string ini_section =
        "[Section]\n"
        "key1 = value1\n"
        "key2 = value2\n";

    typedef client::ini_grammar<string::const_iterator> ini_grammar;
    ini_grammar grammar;
    
    string::const_iterator iter = ini_section.begin();
    string::const_iterator end  = ini_section.end();

    pair<string, vector<pair<string, string>>> result;
    bool r = phrase_parse(iter, end, grammar, blank, result);

    if (r && iter == end)
    {
        cout << "-------------------------\n";
        cout << "Parsing succeeded\n";
        cout << "Section: " << result.first << "\n";
        cout << "Key-Value pairs:\n";
        for (auto& kv : result.second) {
            cout << "  " << kv.first << " = " << kv.second << "\n";
        }
        cout << "-------------------------\n";
    }

    else 
    {
        cout << "-------------------------\n";
        cout << "Parsing failed\n";
        cout << "Remaining unparsed: '" << string(iter, end) << "'\n";
        cout << "-------------------------\n";
    }
    return 0;
}

关键修改说明

  • 调整Skipper:将ascii::space改为ascii::blank,仅跳过空格和制表符,保留换行符让eol能正确匹配。
  • 添加属性类型:为每个规则指定对应属性(字符串、键值对、section结构),同时包含boost/fusion/include/std_pair.hpp让Spirit支持std::pair属性。
  • 完善解析检查:添加结果接收参数,同时验证iter == end确保输入被完全解析。

验证结果

修改后程序运行输出:

-------------------------
Parsing succeeded
Section: Section
Key-Value pairs:
  key1 = value1
  key2 = value2
-------------------------

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 15:07:14