用boost spirit解析boost 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: error: no member named 'insert' in 'boost::uuids::uuid'
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_;
#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}",
如果那是/真的/你想要的,我确实建议使用词法转换实现的两阶段解析操作:
Ok, since it's now more than an hour later, this means that it's more like "10% of the functionality will take 900% of the effort" - I hope you really wanted it :)
#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
我正在尝试用 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: error: no member named 'insert' in 'boost::uuids::uuid' 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_;
#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}",
如果那是/真的/你想要的,我确实建议使用词法转换实现的两阶段解析操作:
Ok, since it's now more than an hour later, this means that it's more like "10% of the functionality will take 900% of the effort" - I hope you really wanted it :)
#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