首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Boost Spirit X3解析X3地址

用Boost Spirit X3解析X3地址
EN

Stack Overflow用户
提问于 2021-02-11 11:17:01
回答 1查看 160关注 0票数 1

这里是X3新手。两个问题:

  1. 为什么结果包含重复的"1,1,1"s,如:<attributes>[[1, 9, 2, ., 1, 6, 8, ., 1, 1, 1, ., 1, 1, 1], [8, 0]]</attributes>,当我期望类似于<attributes>[[1, 9, 2, ., 1, 6, 8, ., 1, ., 1], [8, 0]]</attributes>的东西时
  2. 有什么不太尴尬的方式来定义一个单一的炭被扩展到(对待)?dec_octet规则中的序列。我使用过x3::repeat(1)[x3::digit],但这似乎是错误的,可能会导致第一个问题的错误。(使用x3::repeat(1)[x3::digit]是因为我似乎不能只使用x3::位,因为它会导致规则崩溃?)
代码语言:javascript
复制
#include <iostream>
#include <string>

#define BOOST_SPIRIT_X3_DEBUG
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>


namespace x3 = boost::spirit::x3;

namespace ast
{
    struct ip_port
    {
        std::string host;
        boost::optional<std::string> port;
    };

}
BOOST_FUSION_ADAPT_STRUCT(ast::ip_port, host, port)

namespace parser
{
    template <typename T> auto as = [](auto name, auto p) { return x3::rule<struct _, T> {name} = p; };
    
    const auto dec_octet = as<std::string>("dec_octet",
            (
              x3::char_('2') >> x3::char_('5') >> x3::char_('0', '5')
            | x3::char_('2') >> x3::char_('0', '4') >> x3::digit
            | x3::char_('1') >> x3::digit >> x3::digit          
            | x3::char_('1', '9') >> x3::digit
            | x3::repeat(1)[x3::digit] // awkward way to force sequence from single char, but can't use x3::digit
            )

    );

    const auto ipv4address = as<std::string>("ipv4address",
      dec_octet >> x3::char_('.') >> dec_octet >> x3::char_('.') >> dec_octet >> x3::char_('.') >> dec_octet
    );

    const auto ip = as<std::string>("host", ipv4address);
    const auto port = as<std::string>("port", +x3::digit);
    const auto ip_port = as<ast::ip_port>("ip_port",  ip >> -((':') >> port));
}


template <typename T, typename Parser>
bool parse(const std::string& in, const Parser& p)
{
    T parsed;
    auto iter = in.begin();
    auto end_iter = in.end();
    bool res = x3::parse(iter, end_iter, p, parsed);
    
    return res && (iter == end_iter);
}


int main()
{
    std::cerr << std::boolalpha << parse<ast::ip_port>(std::string{"192.168.1.1:80"}, parser::ip_port) << '\n';
    return EXIT_SUCCESS;    
}

调试输出:

代码语言:javascript
复制
<ip_port>
  <try>192.168.1.1:80</try>
  <host>
    <try>192.168.1.1:80</try>
    <ipv4address>
      <try>192.168.1.1:80</try>
      <dec_octet>
        <try>192.168.1.1:80</try>
        <success>.168.1.1:80</success>
        <attributes>[1, 9, 2]</attributes>
      </dec_octet>
      <dec_octet>
        <try>168.1.1:80</try>
        <success>.1.1:80</success>
        <attributes>[1, 6, 8]</attributes>
      </dec_octet>
      <dec_octet>
        <try>1.1:80</try>
        <success>.1:80</success>
        <attributes>[1, 1, 1]</attributes>
      </dec_octet>
      <dec_octet>
        <try>1:80</try>
        <success>:80</success>
        <attributes>[1, 1, 1]</attributes>
      </dec_octet>
      <success>:80</success>
      <attributes>[1, 9, 2, ., 1, 6, 8, ., 1, 1, 1, ., 1, 1, 1]</attributes>
    </ipv4address>
    <success>:80</success>
    <attributes>[1, 9, 2, ., 1, 6, 8, ., 1, 1, 1, ., 1, 1, 1]</attributes>
  </host>
  <port>
    <try>80</try>
    <success></success>
    <attributes>[8, 0]</attributes>
  </port>
  <success></success>
  <attributes>[[1, 9, 2, ., 1, 6, 8, ., 1, 1, 1, ., 1, 1, 1], [8, 0]]</attributes>
</ip_port>
true

谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-02-11 16:37:02

Q. 1.为什么结果包含重复的" 1,1,1"s,例如:[1,9,2,1,6,8,1,1,1,1,1,1,1,8,0],当我期望这样的结果[1,9,2,.,1,6,8,.,1,.,1,8,0]时

上一次人们遇到这样的陷阱开始已经7天了

这是一个由来已久的“容器属性不是原子的”陷阱:

您可以使用qi::hold对其进行纸张处理。或者你可以修改你的策略。

就像在这种情况下,我建议使用raw来获取底层的源序列。

Q. 2.别那么尴尬..。

中间的步骤是

代码语言:javascript
复制
const auto dec_octet = x3::raw [ x3::uint_parser<uint8_t>{} ];

轰隆隆。使用X3是一个高级解析器生成器这一事实。不要做那些琐碎、容易出错的工作。事实上,你可以简单地

代码语言:javascript
复制
const x3::uint_parser<std::uint8_t> dec_octet{};

这使得“紧张化”发展到了需要的地步:

代码语言:javascript
复制
const x3::uint_parser<std::uint8_t> dec_octet{};
const x3::uint_parser<std::uint16_t> port{};

const auto ipv4address = x3::raw [
      dec_octet >> '.' >> dec_octet >> '.' >> dec_octet >> '.' >> dec_octet ];

const auto ip_port = as<ast::ip_port>("ip_port", ipv4address >> -(':' >> port));

吸脂术后

请注意端口使用uint16_tx3::eoi期望完全解析,删除显式规则/转换:

住在Coliru

代码语言:javascript
复制
#include <iostream>
#include <string>

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/optional/optional_io.hpp>
#include <boost/spirit/home/x3.hpp>

namespace x3 = boost::spirit::x3;

namespace ast {
    struct ip_port {
        std::string host;
        boost::optional<uint16_t> port;
    };
    using boost::fusion::operator<<;
}

BOOST_FUSION_ADAPT_STRUCT(ast::ip_port, host, port)

namespace parser {
    const x3::uint_parser<uint8_t> dec_octet {};
    const x3::uint_parser<uint16_t> port {};

    const auto ipv4address = x3::raw[dec_octet >> '.' >> dec_octet >> '.'
        >> dec_octet >> '.' >> dec_octet];

    const auto ip_port = ipv4address >> -(':' >> port) >> x3::eoi;
}

template <typename Parser, typename Attr>
static inline bool parse(std::string_view in, Parser const& p, Attr& result)
{
    return x3::parse(in.begin(), in.end(), p, result);
}

auto parse_ipport(std::string_view in)
{
    ast::ip_port result;
    if (!parse(in, parser::ip_port, result))
        throw std::invalid_argument("ipv4address");

    return result;
}

int main()
{
    for (auto input : { "192.168.1.1:80", "1.1.1.1", ":" }) {
        std::cerr << parse_ipport(input) << std::endl;
    }
}

打印

代码语言:javascript
复制
(192.168.1.1  80)
(1.1.1.1 --)
terminate called after throwing an instance of 'std::invalid_argument'
  what():  ipv4address
Aborted (core dumped)

将代码简化得更多一些optional

代码语言:javascript
复制
(192.168.1.1 80)
(1.1.1.1 0)
terminate called after throwing an instance of 'std::invalid_argument'
  what():  ipv4address

开箱即用

注意:您的语法不匹配所有符合RFC的ip v4地址。例如。

  • 127.1127.0.0.1有效。
  • 0177.10x7f.1也是

要么真的修复它,要么不要重新发明轮子,使用boost::asio::ip::address_v4::from_string甚至boost::asio::ip::address::from_string,并免费获得IPv6支持。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66153694

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档