簡體   English   中英

用提升精神解析提升 uuid

[英]Parse boost uuids with boost spirit

我正在嘗試使用boost::spirit::qi編寫一個boost::uuids::uuid解析器,以便以一種很好的方式與其他qi解析器一起使用它並擁有一個很好的統一解析器 api。

我的第一個想法是編寫一個自定義qi::grammar它將使用boost::conversion::try_lexical_convert<boost::uuids::uuid &, const std::string &>但是這會存在正確設置開始的問題到消耗位置的迭代器,因為boost::conversion::try_lexical_convert<boost::uuids::uuid &, const std::string &>不僅匹配 16 個字符長的輸入,而且還匹配大括號或​​不帶破折號。

我的第二種方法是使用boost::spirit::qi::rule (或者從boost::spirit::qi::grammar::base_type派生的語法 CRTP,如果你願意的話),但是我得到了編譯錯誤,可能來自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.insert(c.end() , val);

似乎是由boost::spirit::qi::detail::pass_through_container ,但是我將BOOST_FUSION_ADAPT_ADT*(obj.begin()+n)結合使用的方法也因多個錯誤而失敗。

您可以使用內置的qi::stream指令獲得 90% 的路徑:

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

在 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%

根據修改后的帕累托原則,剩下的 10% 是困難的部分。

我什至不確定你是否想要這個,但是+qi::lit("-")意味着也應該接受評論的測試用例(?!):

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

如果那是/真的/你想要的,我確實建議使用詞法轉換實現進行兩階段解析操作:

好的,因為現在已經過了一個多小時,這意味着它更像是“10% 的功能需要 900% 的努力”——我希望你真的想要它:)

住在 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM