代码之家  ›  专栏  ›  技术社区  ›  Superlokkus

使用boostspirit解析boostuuid

  •  1
  • Superlokkus  · 技术社区  · 7 年前

    我正试着写一本书 boost::uuids::uuid boost::spirit::qi 为了更好地与其他人一起使用它 qi 解析器和有一个很好的统一解析器api。

    我的第一个想法是写一个习惯 qi::grammar 用哪一个 boost::conversion::try_lexical_convert<boost::uuids::uuid &, const std::string &> 但是,这会有将begin迭代器正确设置为consumed位置的问题,因为 将不仅匹配16个字符长的输入,而且还匹配带大括号或不带破折号的输入。

    我的第二种方法是使用 boost::spirit::qi::rule boost::spirit::qi::grammar::base_type 如果你愿意的话),但是我得到了编译错误,可能来自 BOOST_FUSION_ADAPT_STRUCT 表达方式:

        #include <iostream>
        #include <string>
        #include <cstdint>
        #include <boost/uuid/uuid.hpp>
        #include <boost/spirit/include/qi.hpp>
    
    
        BOOST_FUSION_ADAPT_STRUCT(
                boost::uuids::uuid,
                (uint8_t, data[0])
                (uint8_t, data[1])
                (uint8_t, data[2])
                (uint8_t, data[3])
                (uint8_t, data[4])
                (uint8_t, data[5])
                (uint8_t, data[6])
                (uint8_t, data[7])
                (uint8_t, data[8])
                (uint8_t, data[9])
                (uint8_t, data[10])
                (uint8_t, data[11])
                (uint8_t, data[12])
                (uint8_t, data[13])
                (uint8_t, data[14])
                (uint8_t, data[15])
        )
    
        template<typename Iterator>
        boost::spirit::qi::rule<Iterator, boost::uuids::uuid>
                uuid_internal_{
                boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                        //time-low
                        >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                        >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                        >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                        >> -boost::spirit::qi::lit("-")
                        //time-mid
                        >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                        >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                        >> -boost::spirit::qi::lit("-")
                        //time-high-and-version
                        >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                        >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                        >> -boost::spirit::qi::lit("-")
                        >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>() //clock-seq-and-reserved
                        >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>() //clock-seq-low
                        >> -boost::spirit::qi::lit("-")
                        //node
                        >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                        >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                        >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                        >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                        >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                        >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
        };
    
        template<typename Iterator>
        struct uuid_
                : ::boost::spirit::qi::grammar<Iterator, boost::uuids::uuid()>{
            uuid_() : uuid_::base_type(start) {
    
                start %= (boost::spirit::qi::lit("{") >> uuid_internal_ >> boost::spirit::qi::lit("}")) |
                         uuid_internal_ ;
            }
    
            boost::spirit::qi::rule<Iterator, boost::uuids::uuid()> start;
    
            boost::spirit::qi::rule<Iterator, boost::uuids::uuid()>
                    uuid_internal_{
                    boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                            //time-low
                            >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                            >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                            >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                            >> -boost::spirit::qi::lit("-")
                            //time-mid
                            >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                            >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                            >> -boost::spirit::qi::lit("-")
                            //time-high-and-version
                            >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                            >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                            >> -boost::spirit::qi::lit("-")
                            >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>() //clock-seq-and-reserved
                            >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>() //clock-seq-low
                            >> -boost::spirit::qi::lit("-")
                            //node
                            >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                            >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                            >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                            >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                            >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
                            >> boost::spirit::qi::uint_parser<uint8_t, 16, 1, 1>()
            };
    
        };
    
        int main() {
            std::string input;
            std::cin >> input;
            uuid_<std::string::const_iterator> uuid_{};
            boost::uuids::uuid uuid{};
            auto begin = input.begin(), end = input.end();
    
            const bool success = boost::spirit::qi::parse(begin, end, uuid_, uuid);
            if (!success || begin != end)
                throw std::runtime_error("Parsing failed");
    
            return 0;
    
    
        }
    

    /opt/local/include/boost/spirit/home/support/container.hpp:292:15:错误:boost::uuids::uuid中没有名为“insert”的成员 c、 插入(c.end(),val);

    似乎是由生成的 boost::spirit::qi::detail::pass_through_container 然而,我的方法 BOOST_FUSION_ADAPT_ADT 结合 *(obj.begin()+n) 也因多个错误而失败。

    1 回复  |  直到 7 年前
        1
  •  2
  •   sehe    7 年前

    你可以使用内置的 qi::stream 指令以获得90%的方式:

    uuid_ = qi::stream;
    start = '{' >> uuid_ >> '}' | uuid_;
    

    看到了吗 Live On Coliru

    #include <boost/spirit/include/qi.hpp>
    #include <boost/uuid/uuid_io.hpp>
    #include <iomanip>
    
    namespace qi = boost::spirit::qi;
    
    template <typename Iterator> struct uuid_type : ::qi::grammar<Iterator, boost::uuids::uuid()> {
        uuid_type() : uuid_type::base_type(start) {
    
            start = '{' >> uuid_ >> '}' | uuid_;
            uuid_ = qi::stream;
        }
      private:
        qi::rule<Iterator, boost::uuids::uuid()> start, uuid_;
    };
    
    int main() {
        uuid_type<std::string::const_iterator> uuid_{};
    
        for (std::string const input : {
                "2bc69ead-4aba-4a39-92c0-9565f4d464b4",
                "2BC69EAD-4ABA-4A39-92C0-9565F4D464B4",
                "{2bc69ead-4aba-4a39-92c0-9565f4d464b4}",
                "{2BC69EAD-4ABA-4A39-92C0-9565F4D464B4}",
                //"{2bc69ead--4aba--4a39----92c0--9565f4d464b4}",
                //"{2BC69EAD--4ABA--4A39----92C0--9565F4D464B4}",
                })
        {
            boost::uuids::uuid uuid{};
    
            std::cout << "==== Input " << std::quoted(input) << "\n";
    
            if (qi::parse(input.begin(), input.end(), uuid_ >> qi::eoi, uuid))
                std::cout << "Parsed " << uuid << "\n";
            else
                std::cout << "Parsing failed\n";
        }
    }
    

    ==== Input "2bc69ead-4aba-4a39-92c0-9565f4d464b4"
    Parsed 2bc69ead-4aba-4a39-92c0-9565f4d464b4
    ==== Input "2BC69EAD-4ABA-4A39-92C0-9565F4D464B4"
    Parsed 2bc69ead-4aba-4a39-92c0-9565f4d464b4
    ==== Input "{2bc69ead-4aba-4a39-92c0-9565f4d464b4}"
    Parsed 2bc69ead-4aba-4a39-92c0-9565f4d464b4
    ==== Input "{2BC69EAD-4ABA-4A39-92C0-9565F4D464B4}"
    Parsed 2bc69ead-4aba-4a39-92c0-9565f4d464b4
    

    剩下的10%

    根据 modified Pareto principle 剩下的10%是最难的部分。

    我甚至不确定你想要这个,但是 +qi::lit("-") 表示也应接受已注释的测试用例(?!)

            //"{2bc69ead--4aba--4a39----92c0--9565f4d464b4}",
            //"{2BC69EAD--4ABA--4A39----92C0--9565F4D464B4}",
    

    如果这是/真的/你想要的,我确实建议使用词法转换实现进行两阶段解析操作:

    好的,因为现在已经晚了一个多小时,这意味着它更像是“10%的功能将花费900%的精力”-我希望你真的想要它:)

    Live On Coliru

    #include <boost/spirit/include/qi.hpp>
    #include <boost/lexical_cast.hpp>
    #include <boost/uuid/uuid_io.hpp>
    #include <iomanip>
    
    using Uuid = boost::uuids::uuid;
    
    namespace boost::spirit::traits {
        template <> struct is_container<Uuid> : mpl::false_ {};
    
        template <> struct assign_to_attribute_from_value<Uuid, std::string> {
            static void call(std::string const& s, Uuid& v) { v = lexical_cast<Uuid>(s); }
        };
    }
    
    namespace qi = boost::spirit::qi;
    
    template <typename Iterator> struct uuid_type : qi::grammar<Iterator, Uuid()> {
        uuid_type() : uuid_type::base_type(start) {
            using namespace qi;
    
            auto sep_  = copy(+lit('-') >> qi::attr('-'));
            auto hex2_ = copy(xdigit >> xdigit >> xdigit >> xdigit);
            auto hex4_ = copy(hex2_ >> hex2_);
            auto hex6_ = copy(hex4_ >> hex2_);
            auto fmt_  = copy(
                hex4_ >> sep_ >> hex2_ >> sep_ >> hex2_ >> sep_ >> hex2_ >> sep_ >> hex6_
            );
    
            start = as_string['{' >> fmt_ >> '}' | fmt_];
        }
      private:
        qi::rule<Iterator, Uuid()> start;
    };
    
    int main() {
        uuid_type<std::string::const_iterator> uuid_{};
    
        for (std::string const input : {
                "2bc69ead-4aba-4a39-92c0-9565f4d464b4",
                "2BC69EAD-4ABA-4A39-92C0-9565F4D464B4",
                "{2bc69ead-4aba-4a39-92c0-9565f4d464b4}",
                "{2BC69EAD-4ABA-4A39-92C0-9565F4D464B4}",
                "{2bc69ead--4aba--4a39----92c0--9565f4d464b4}",
                "{2BC69EAD--4ABA--4A39----92C0--9565F4D464B4}",
                })
        {
            Uuid uuid{};
    
            std::cout << "==== Input " << std::quoted(input) << "\n";
    
            auto f = input.begin(), l = input.end();
            if (qi::parse(f, l, uuid_ >> qi::eoi, uuid))
                std::cout << "Parsed " << uuid << "\n";
            else
                std::cout << "Parsing failed\n";
        }
    }
    

    印刷品

    ==== Input "2bc69ead-4aba-4a39-92c0-9565f4d464b4"
    Parsed 2bc69ead-4aba-4a39-92c0-9565f4d464b4
    ==== Input "2BC69EAD-4ABA-4A39-92C0-9565F4D464B4"
    Parsed 2bc69ead-4aba-4a39-92c0-9565f4d464b4
    ==== Input "{2bc69ead-4aba-4a39-92c0-9565f4d464b4}"
    Parsed 2bc69ead-4aba-4a39-92c0-9565f4d464b4
    ==== Input "{2BC69EAD-4ABA-4A39-92C0-9565F4D464B4}"
    Parsed 2bc69ead-4aba-4a39-92c0-9565f4d464b4
    ==== Input "{2bc69ead--4aba--4a39----92c0--9565f4d464b4}"
    Parsed 2bc69ead-4aba-4a39-92c0-9565f4d464b4
    ==== Input "{2BC69EAD--4ABA--4A39----92C0--9565F4D464B4}"
    Parsed 2bc69ead-4aba-4a39-92c0-9565f4d464b4