获取INI文件行号的跨平台方法,其中找到了给定选项 查找一些C++库(如Booo::程序选项),它能够返回INI文件的行号,在这里找到给定的选项或部分。

获取INI文件行号的跨平台方法,其中找到了给定选项 查找一些C++库(如Booo::程序选项),它能够返回INI文件的行号,在这里找到给定的选项或部分。,c++,parsing,boost,ini,C++,Parsing,Boost,Ini,用例: 我要求该库在“[SSS]”节中查找值“vvv”。库返回在“[SSS]”节中找到“vvv”的行号,或-1。它让我能够说“第55行:vvv必须小于256” 我迭代INI文件中的部分并验证它们的名称。当发现一些疯狂的秘密时,我告诉他:“第55行:部分[哈哈哈]是未知的” 更新:我知道“INI比mammoth更老”,但目前我不得不将大型windows项目移植到跨平台,无法很快删除.INI文件。再次利用这个机会与Boost Spirit一起玩。这一次我要和你一起玩 我的劳动成果如下: 当POSI

用例:

  • 我要求该库在“[SSS]”节中查找值“vvv”。库返回在“[SSS]”节中找到“vvv”的行号,或-1。它让我能够说“第55行:vvv必须小于256”

  • 我迭代INI文件中的部分并验证它们的名称。当发现一些疯狂的秘密时,我告诉他:“第55行:部分[哈哈哈]是未知的”


  • 更新:我知道“INI比mammoth更老”,但目前我不得不将大型windows项目移植到跨平台,无法很快删除.INI文件。

    再次利用这个机会与Boost Spirit一起玩。这一次我要和你一起玩

    我的劳动成果如下:

    • POSITIONINFO==0时
      • 输入是流式的
      • 输出为原始字符串(好的,
        map
        用于部分)
    • POSITIONINFO==1

      • 输入被缓冲
      • 输出为
        textnode\t

        struct textnode_t {
            int sline, eline, scol, ecol;
            string_t text;
        };
        
        这意味着生成的
        map
        能够准确地报告标记各个文本节点的起点和终点(行、列)请参见演示的测试输出

      • 注释(
        #
        /*…*/
        样式)已经实现

      • 空白是“允许的”

        name=value#使用注释强制包含尾随空格 可选项=用斜杠转义\

      • 将斜杠的反转义作为练习

      • 如果启用,还将使用完整位置信息报告错误
    注意C++11支持不是必需的,但我使用它来转储解析结果。我太懒了,不能用C++03详细迭代器风格编写它。:)

    所有代码、makefile、example.ini均可在此处找到:

    代码 演示输出(位置信息==0) 演示输出(位置信息==1)
    INI文件是一种不推荐使用的windows特定格式-使用跨平台的方式来解析它们有点奇怪。@MadKeithV:虽然这种格式在windows世界中最流行,但没有什么能阻止它在每个有文本文件的平台上使用(这是最确定的)。此外,大多数变体都非常简单,即使还没有跨平台库,也可以实际解析自己。@delnan-我没有说有任何东西阻止您使用它,只是想使用它很奇怪。如果你陷入这种不幸的现实,你将不得不解析INI文件,但是如果你有选择,为什么不选择一种更好的格式呢?@MadKeithV:是的,因为PHP和MySQL是windows特有的工具。哦,等等。@MadKeithV:我可能是老式的,但对于简单的键值对,我看INI没有任何错误,这些键值对可能被分类在一个平面名称空间中。无需引入完整的XML(JSON、YAML等)解析器(可能还需要另一个库以便更轻松地处理—是否处理过原始的XML DOM?)。哪些格式更好,它们如何更好?
    /* inireader.h */
    #pragma once
    
    #define POSITIONINFO 0
    
    #include <map>
    #include <string>
    #include <iterator>
    #include <boost/tuple/tuple_comparison.hpp>
    
    template <typename S=std::string, typename Cmp=std::less<S> >
        class IniFile
    {
        public:
        IniFile(Cmp cmp=Cmp()) : _cmp(cmp) 
            {}
    
        IniFile(const std::string& filename, Cmp cmp=Cmp()) : _cmp(cmp)
            { open(filename); }
    
        void open(const std::string& filename);
    
        typedef S string_t;
    #if POSITIONINFO
        struct textnode_t
        {
            int sline, eline,
                scol, ecol;
            string_t text;
    
            operator const string_t&() const { return text; }
            friend std::ostream& operator<<(std::ostream& os, const textnode_t& t)
            { 
                os << "[L:" << t.sline << ",C" << t.scol << " .. L" << t.eline << ",C" << t.ecol << ":";
                for (typename string_t::const_iterator it=t.text.begin(); it!=t.text.end(); ++it)
                switch (*it)
                {
                    case '\r' : os << "\\r"; break;
                    case '\n' : os << "\\n"; break;
                    case '\t' : os << "\\t"; break;
                    case '\0' : os << "\\0"; break;
                    default:    os << *it  ; break;
                }
                return os << "]"; 
            }
    
            bool operator<(const textnode_t& o) const 
                { return boost::tie(text/*, sline, eline, scol, ecol*/) <
                         boost::tie(o.text/*, o.sline, o.eline, o.scol, o.ecol*/); }
    
            textnode_t() : sline(0), eline(0), scol(0), ecol(0) { }
        };
    #else
        typedef string_t textnode_t;
    #endif
    
        typedef std::pair<textnode_t, textnode_t>   keyvalue_t;
        typedef std::map<textnode_t, textnode_t>    section_t;
        typedef std::map<textnode_t, section_t> sections_t;
    
      private:
        Cmp _cmp;
    };
    
    ///////////////////////////////////////
    // template implementation
    //#define BOOST_SPIRIT_DEBUG
    
    #include <boost/spirit/include/qi.hpp>
    #include <boost/spirit/include/support_istream_iterator.hpp>
    #include <boost/spirit/include/support_line_pos_iterator.hpp>
    #include <boost/spirit/include/phoenix.hpp>
    #include <boost/fusion/adapted/std_pair.hpp>
    #include <fstream>
    
    namespace qi = boost::spirit::qi;
    namespace phx= boost::phoenix;
    
    namespace inireader
    {
        struct printer
        {
            printer(std::ostream& os) : _os(os) {}
            std::ostream& _os;
    
            typedef boost::spirit::utf8_string string;
    
            void element(string const& tag, string const& value, int depth) const
            {
                for (int i = 0; i < (depth*4); ++i) // indent to depth
                    _os << ' ';
    
                _os << "tag: " << tag;
                if (value != "")
                    _os << ", value: " << value;
                _os << std::endl;
            }
        };
    
        void print_info(std::ostream& os, boost::spirit::info const& what)
        {
            using boost::spirit::basic_info_walker;
    
            printer pr(os);
            basic_info_walker<printer> walker(pr, what.tag, 0);
            boost::apply_visitor(walker, what.value);
        }
    
        template <typename It, typename Skipper, typename Ini>
            struct Grammar : qi::grammar<It, typename Ini::sections_t(), Skipper>
        {
            typedef typename Ini::string_t string_t;
            typedef typename Ini::textnode_t textnode_t;
    
            struct textbuilder
            {
                template <typename> struct result { typedef textnode_t type; };
    
                textbuilder(It begin) : _begin(begin) { }
    
                textnode_t operator()(const boost::iterator_range<It>& iters) const
                {
    #if !POSITIONINFO
                    return textnode_t(std::begin(iters), std::end(iters));
    #else
                    using boost::spirit::get_line;
                    using boost::spirit::get_line_start;
                    using boost::spirit::get_column;
    
                    textnode_t element;
                    element.text  = string_t       (std::begin(iters)  , std::end(iters));
                    element.sline = get_line       (std::begin(iters));
                    element.eline = get_line       (std::end(iters));
                    It sol        = get_line_start (_begin             , std::begin(iters));
                    element.scol  = get_column     (sol                , std::begin(iters));
                    element.ecol  = get_column     (sol                , std::end(iters));
    
                    return element;
    #endif
                }
    
              private: 
                const It _begin;
            } makenode;
    
            Grammar(It begin) : Grammar::base_type(inifile), makenode(begin)
            {
                using namespace qi;
                txt_ch = (lit('\\') > char_) | (char_ - (eol | '#' | "/*"));
    
                key     = raw [ lexeme [ +(txt_ch - char_("=")) ] ] [ _val = phx::bind(makenode, _1) ];
                value   = raw [ lexeme [ +txt_ch ] ]                [ _val = phx::bind(makenode, _1) ];
                pair   %= key > '=' > value;
    
                heading  = ('[' > raw [ +~char_(']') ] > ']') [ _val = phx::bind(makenode, _1) ];
                section %= heading >> +eol >> -((pair-heading) % +eol);
                inifile %= -(section % +eol) >> *eol > eoi;
    
                comment = 
                      ('#' >> *(char_ - eol))
                    | ("/*" > *(char_ - "*/") > "*/");
    
                //BOOST_SPIRIT_DEBUG_NODE(comment);
                //BOOST_SPIRIT_DEBUG_NODE(txt_ch);
                BOOST_SPIRIT_DEBUG_NODE(heading);
                BOOST_SPIRIT_DEBUG_NODE(section);
                BOOST_SPIRIT_DEBUG_NODE(key);
                BOOST_SPIRIT_DEBUG_NODE(value);
                BOOST_SPIRIT_DEBUG_NODE(pair);
                BOOST_SPIRIT_DEBUG_NODE(inifile);
            }
    
            typedef typename Ini::keyvalue_t keyvalue_t;
            typedef typename Ini::section_t  section_t;
            typedef typename Ini::sections_t sections_t;
            typedef typename string_t::value_type Char;
            qi::rule<It>                        comment;
            qi::rule<It, Char()>                txt_ch;
            qi::rule<It, textnode_t(), Skipper> key, value, heading;
            qi::rule<It, keyvalue_t(), Skipper> pair;
            qi::rule<It, std::pair<textnode_t, section_t>(), Skipper> section;
            qi::rule<It, sections_t(), Skipper> inifile;
        };
    
        template <typename It, typename Builder>
            typename Builder::template result<void>::type
                fragment(const It& first, const It& last, const Builder& builder)
                {
                    size_t len = std::distance(first, last);
                    It frag_end = first;
                    std::advance(frag_end, std::min(10ul, len));
                    return builder(boost::iterator_range<It>(first, frag_end));
                }
    }
    
    template <typename S, typename Cmp>
    void IniFile<S, Cmp>::open(const std::string& filename)
    {
        using namespace qi;
    
        std::ifstream ifs(filename.c_str());
        ifs.unsetf(std::ios::skipws);
    
    #if POSITIONINFO
        typedef std::string::const_iterator RawIt;
        typedef boost::spirit::line_pos_iterator<RawIt> It;
    
        typedef rule<It> Skipper;
    
        std::string buffer(std::istreambuf_iterator<char>(ifs), (std::istreambuf_iterator<char>()));
        It f(buffer.begin()), l(buffer.end());
    #else
        typedef boost::spirit::istream_iterator It;
        typedef rule<It> Skipper;
    
        It f(ifs), l;
    #endif
    
        inireader::Grammar<It, Skipper, IniFile<S, Cmp> > grammar(f);
        Skipper skip = char_(" \t") | grammar.comment;
    
        try
        {
            sections_t data;
            bool ok = phrase_parse(f, l, grammar, skip, data);
            if (ok)
            {
                std::cout << "Parse success!" << std::endl;
    
    ///////// C++11 specific features for quick display //////////
                for (auto& section : data)
                {
                    std::cout << "[" << section.first << "]" << std::endl;
                    for (auto& pair : section.second)
                        std::cout << pair.first << " = " << pair.second << std::endl;
    ///////// End C++11 specific /////////////////////////////////
                }
            } else
            {
                std::cerr << "Parse failed" << std::endl;
            }
        } catch (const qi::expectation_failure<It>& e)
        {
            std::cerr << "Exception: " << e.what() << 
                  " " << inireader::fragment(e.first, e.last, grammar.makenode) << "... ";
            inireader::print_info(std::cerr, e.what_);
        }
        if (f!=l)
        {
            std::cerr << "Stopped at: '" << inireader::fragment(f, l, grammar.makenode) << "'" << std::endl;
        }
    }
    
    [Cat1]
    name1=100 #skipped
    
    name2=200 \#not \\skipped
    name3=   dhfj dhjgfd/* skipped
    
    */
    
    [Cat_2]
    UsagePage=9
    Usage=19
    Offset=0x1204
    
    /*
    [Cat_2_bak]
    UsagePage=9
    Usage=19
    Offset=0x1204
    */
    
    [Cat_3]
    UsagePage=12
    Usage=39
    #Usage4=39
    Offset=0x12304
    
    Parse success!
    [Cat1]
    name1 = 100 
    name2 = 200 \#not \\skipped
    name3 = dhfj dhjgfd
    [Cat_2]
    Offset = 0x1204
    Usage = 19
    UsagePage = 9
    [Cat_3]
    Offset = 0x12304
    Usage = 39
    UsagePage = 12
    
    Parse success!
    [[L:1,C2 .. L1,C6:Cat1]]
    [L:2,C2 .. L2,C7:name1] = [L:2,C8 .. L2,C12:100 ]
    [L:6,C2 .. L6,C7:name2] = [L:6,C8 .. L6,C27:200 \#not \\skipped]
    [L:7,C2 .. L7,C7:name3] = [L:7,C11 .. L7,C22:dhfj dhjgfd]
    [[L:13,C3 .. L13,C8:Cat_2]]
    [L:16,C2 .. L16,C8:Offset] = [L:16,C9 .. L16,C15:0x1204]
    [L:15,C2 .. L15,C7:Usage] = [L:15,C8 .. L15,C10:19]
    [L:14,C2 .. L14,C11:UsagePage] = [L:14,C12 .. L14,C13:9]
    [[L:25,C3 .. L25,C8:Cat_3]]
    [L:29,C2 .. L29,C8:Offset] = [L:29,C9 .. L29,C16:0x12304]
    [L:27,C2 .. L27,C7:Usage] = [L:27,C8 .. L27,C10:39]
    [L:26,C2 .. L26,C11:UsagePage] = [L:26,C12 .. L26,C14:12]