使用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; }
问题原因分析
- 空格处理冲突:
phrase_parse使用的ascii::spaceskipper会自动跳过所有空白字符(包括换行),但代码中显式写了>> '\n'要求匹配换行符,此时换行已被skipper吃掉,导致匹配失败。 - 规则属性缺失:所有规则未定义属性类型,解析器无法捕获匹配结果,调试输出中
<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
相关产品推荐
相关产品推荐

