C++ 学习动力。精神:解析INI

C++ 学习动力。精神:解析INI,c++,boost,boost-spirit,boost-spirit-qi,C++,Boost,Boost Spirit,Boost Spirit Qi,我开始学习提高精神,并完成阅读部分。阅读时,一切都简单易懂。但是当我尝试做一些事情时,会出现很多错误,因为包含和名称空间太多,我需要知道何时包含/使用它们。作为实践,我想编写简单的INI解析器 以下是代码(包括Spirit lib中的一个示例以及几乎所有其他内容): 我失败了,std::string(iter,end)是完整的输入字符串 我的问题是: 为什么我看到失败但没有看到错误处理程序上的 你对如何学习Boost.Spirit有什么建议吗(我在理论上对文档有很好的理解,但在实践中我有很多原

我开始学习提高精神,并完成阅读部分。阅读时,一切都简单易懂。但是当我尝试做一些事情时,会出现很多错误,因为包含和名称空间太多,我需要知道何时包含/使用它们。作为实践,我想编写简单的INI解析器

以下是代码(包括Spirit lib中的一个示例以及几乎所有其他内容):

我失败了,
std::string(iter,end)
是完整的输入字符串

我的问题是:

  • 为什么我看到失败但没有看到错误处理程序上的
  • 你对如何学习Boost.Spirit有什么建议吗(我在理论上对文档有很好的理解,但在实践中我有很多原因
谢谢

Q.为什么我在错误处理程序上看到失败但没有看到

on_错误处理程序仅针对已注册的规则(第u节)启动,并且如果为

您的语法不包含期望点(仅使用
>
,而不是
>

Q.你对如何学习Boost.Spirit有什么建议吗(我在理论上对文档有很好的理解,但在实践中我有很多原因

只需构建所需的解析器。从文档中复制好的约定,然后回答。有很多。正如您所看到的,相当多的Ini解析器包含了完整的示例,并且具有不同级别的错误报告

奖励提示: 执行更详细的状态报告:

bool ok = phrase_parse(iter, end, grammar, space, ini);

if (ok) {
    std::cout << "Parse success\n";
} else {
    std::cout << "Parse failure\n";
}

if (iter != end) {
    std::cout << "Remaining unparsed: '" << std::string(iter, end) << "'\n";
}

return ok && (iter==end)? 0 : 1;
印刷品:

<section_>
  <try>[section]\nkey1=val1\n</try>
  <key_>
    <try>section]\nkey1=val1\nk</try>
    <success>]\nkey1=val1\nkey2=val</success>
    <attributes>[[s, e, c, t, i, o, n]]</attributes>
  </key_>
  <fail/>
</section_>
Parse failure
Remaining unparsed: '[section]
key1=val1
key2=val2
'
注意:解析成功,但没有执行您想要的操作。这是因为
*char.
包含换行符。那就这样吧

       pair_ = key_ >> '=' >> *(char_ - qi::eol); // or
       pair_ = key_ >> '=' >> *~char_("\r\n"); // etc
完整代码

#define BOOST_SPIRIT_DEBUG
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/phoenix_object.hpp>

#include <iostream>
#include <string>
#include <vector>
#include <map>

namespace client
{
    typedef std::map<std::string, std::string> key_value_map_t;

    struct mini_ini
    {
        std::string name;
        key_value_map_t key_values_map;
    };
} // client

BOOST_FUSION_ADAPT_STRUCT(
    client::mini_ini,
    (std::string, name)
    (client::key_value_map_t, key_values_map)
)

namespace client
{
    namespace qi      = boost::spirit::qi;
    namespace ascii   = boost::spirit::ascii;
    namespace phoenix = boost::phoenix;

    template <typename Iterator>
    struct ini_grammar : qi::grammar<Iterator, mini_ini(), ascii::blank_type>
    {
        ini_grammar() : ini_grammar::base_type(section_, "section")
        {
            using qi::char_;
            using qi::on_error;
            using qi::fail;
            using namespace qi::labels;
            using phoenix::construct;
            using phoenix::val;

            key_ = +char_("a-zA-Z_0-9");
            pair_ = key_ >> '=' >> *char_;
            section_ = '[' >> key_ >> ']' >> '\n' >> *(pair_ >> '\n');

            BOOST_SPIRIT_DEBUG_NODES((key_)(pair_)(section_))

            on_error<fail>
            (
                section_
              , std::cout
                    << val("Error! Expecting ")
                    << _4                               // what failed?
                    << val(" here: \"")
                    << construct<std::string>(_3, _2)   // iterators to error-pos, end
                    << val("\"")
                    << std::endl
            );
        }

        qi::rule<Iterator, std::string(), ascii::blank_type> key_;
        qi::rule<Iterator, mini_ini(), ascii::blank_type> section_;
        qi::rule<Iterator, std::pair<std::string, std::string>(), ascii::blank_type> pair_;
    };
} // client

int
main()
{
    std::string storage =
        "[section]\n"
        "key1=val1\n"
        "key2=val2\n";
    client::mini_ini ini;
    typedef client::ini_grammar<std::string::const_iterator> ini_grammar;
    ini_grammar grammar;

    using boost::spirit::ascii::blank;
    std::string::const_iterator iter = storage.begin();
    std::string::const_iterator end = storage.end();
    bool ok = phrase_parse(iter, end, grammar, blank, ini);

    if (ok) {
        std::cout << "Parse success\n";
    } else {
        std::cout << "Parse failure\n";
    }

    if (iter != end) {
        std::cout << "Remaining unparsed: '" << std::string(iter, end) << "'\n";
    }

    return ok && (iter==end)? 0 : 1;
}
#定义BOOST\u SPIRIT\u DEBUG
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
命名空间客户端
{
typedef std::map key\u value\u map\t;
结构迷你_ini
{
std::字符串名;
键值映射键值映射;
};
}//客户端
增强融合适应结构(
客户端::mini_ini,
(std::字符串,名称)
(客户端::关键值映射,关键值映射)
)
命名空间客户端
{
名称空间qi=boost::spirit::qi;
名称空间ascii=boost::spirit::ascii;
名称空间phoenix=boost::phoenix;
模板
结构ini_语法:qi::grammar
{
ini_语法():ini_语法::基本类型(节,“节”)
{
使用qi::char\ux;
使用qi::on_错误;
使用qi::失败;
使用名称空间qi::标签;
使用phoenix::构造;
使用phoenix::val;
键=+字符(“a-zA-Z_0-9”);
配对=键='>>'='>>*字符;
节\='['>>键\'>']'>'\n'>>*(对\>>'\n');
BOOST_SPIRIT_DEBUG_节点((键)(对)(节))
论错误
(
部分_
,std::cout

也要…是的。你只是忘了搜索所以:)
<section_>
  <try>[section]\nkey1=val1\n</try>
  <key_>
    <try>section]\nkey1=val1\nk</try>
    <success>]\nkey1=val1\nkey2=val</success>
    <attributes>[[s, e, c, t, i, o, n]]</attributes>
  </key_>
  <fail/>
</section_>
Parse failure
Remaining unparsed: '[section]
key1=val1
key2=val2
'
<section_>
<try>[section]\nkey1=val1\n</try>
<key_>
    <try>section]\nkey1=val1\nk</try>
    <success>]\nkey1=val1\nkey2=val</success>
    <attributes>[[s, e, c, t, i, o, n]]</attributes>
</key_>
<pair_>
    <try>key1=val1\nkey2=val2\n</try>
    <key_>
    <try>key1=val1\nkey2=val2\n</try>
    <success>=val1\nkey2=val2\n</success>
    <attributes>[[k, e, y, 1]]</attributes>
    </key_>
    <success></success>
    <attributes>[[[k, e, y, 1], [v, a, l, 1, 
, k, e, y, 2, =, v, a, l, 2, 
]]]</attributes>
</pair_>
<success>key1=val1\nkey2=val2\n</success>
<attributes>[[[s, e, c, t, i, o, n], []]]</attributes>
</section_>
Parse success
Remaining unparsed: 'key1=val1
key2=val2
       pair_ = key_ >> '=' >> *(char_ - qi::eol); // or
       pair_ = key_ >> '=' >> *~char_("\r\n"); // etc
#define BOOST_SPIRIT_DEBUG
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/phoenix_object.hpp>

#include <iostream>
#include <string>
#include <vector>
#include <map>

namespace client
{
    typedef std::map<std::string, std::string> key_value_map_t;

    struct mini_ini
    {
        std::string name;
        key_value_map_t key_values_map;
    };
} // client

BOOST_FUSION_ADAPT_STRUCT(
    client::mini_ini,
    (std::string, name)
    (client::key_value_map_t, key_values_map)
)

namespace client
{
    namespace qi      = boost::spirit::qi;
    namespace ascii   = boost::spirit::ascii;
    namespace phoenix = boost::phoenix;

    template <typename Iterator>
    struct ini_grammar : qi::grammar<Iterator, mini_ini(), ascii::blank_type>
    {
        ini_grammar() : ini_grammar::base_type(section_, "section")
        {
            using qi::char_;
            using qi::on_error;
            using qi::fail;
            using namespace qi::labels;
            using phoenix::construct;
            using phoenix::val;

            key_ = +char_("a-zA-Z_0-9");
            pair_ = key_ >> '=' >> *char_;
            section_ = '[' >> key_ >> ']' >> '\n' >> *(pair_ >> '\n');

            BOOST_SPIRIT_DEBUG_NODES((key_)(pair_)(section_))

            on_error<fail>
            (
                section_
              , std::cout
                    << val("Error! Expecting ")
                    << _4                               // what failed?
                    << val(" here: \"")
                    << construct<std::string>(_3, _2)   // iterators to error-pos, end
                    << val("\"")
                    << std::endl
            );
        }

        qi::rule<Iterator, std::string(), ascii::blank_type> key_;
        qi::rule<Iterator, mini_ini(), ascii::blank_type> section_;
        qi::rule<Iterator, std::pair<std::string, std::string>(), ascii::blank_type> pair_;
    };
} // client

int
main()
{
    std::string storage =
        "[section]\n"
        "key1=val1\n"
        "key2=val2\n";
    client::mini_ini ini;
    typedef client::ini_grammar<std::string::const_iterator> ini_grammar;
    ini_grammar grammar;

    using boost::spirit::ascii::blank;
    std::string::const_iterator iter = storage.begin();
    std::string::const_iterator end = storage.end();
    bool ok = phrase_parse(iter, end, grammar, blank, ini);

    if (ok) {
        std::cout << "Parse success\n";
    } else {
        std::cout << "Parse failure\n";
    }

    if (iter != end) {
        std::cout << "Remaining unparsed: '" << std::string(iter, end) << "'\n";
    }

    return ok && (iter==end)? 0 : 1;
}