使用 boost-spirit 解析 ipv4 地址
Posted
技术标签:
【中文标题】使用 boost-spirit 解析 ipv4 地址【英文标题】:Parsing ipv4 addresses using boost-spirit 【发布时间】:2012-07-03 09:19:01 【问题描述】:我想使用 boost::spirit 来解析 ipv4 地址。这是我尝试做的:
#include <string>
#include <string.h>
#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
struct Ipv4 union uint32_t as_int; uint8_t as_char[4]; raw; ;
Ipv4 make_ipv4(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4)
Ipv4 ip;
ip.raw.as_char[0] = i1; ip.raw.as_char[1] = i2;
ip.raw.as_char[2] = i3; ip.raw.as_char[3] = i4;
return ip;
namespace qi = boost::spirit::qi;
qi::uint_parser<uint8_t, 10, 1, 3> octet;
struct Ipv4Address : qi::grammar<const char *, Ipv4()>
Ipv4Address() : Ipv4Address::base_type(start)
start = ( octet >> qi::lit('.') >> octet >> qi::lit('.') >>
octet >> qi::lit('.') >> octet
) [
//qi::_val = make_ipv4(1, 2, 3, 4) // working
qi::_val = make_ipv4(qi::_1, qi::_2, qi::_3, qi::_4) // compile error
]
;
qi::rule<const char *, Ipv4()> start;
ipv4_address;
int main()
Ipv4 ip;
const char * s = "1.2.3.4";
bool r = qi::parse(s, s+strlen(s), ipv4_address, ip);
std::cout << r << " " << (int)ip.raw.as_char[0] << "." <<
(int)ip.raw.as_char[1] << "." <<
(int)ip.raw.as_char[2] << "." <<
(int)ip.raw.as_char[3] << std::endl;
编译时出现以下编译错误:
/tmp/ip.cxx:在构造函数“Ipv4Address::Ipv4Address()”中: /tmp/ip.cxx:26:72:错误:无法转换'const _1_type aka const boost::phoenix::actor >' 到 'uint8_t aka unsigned char' 用于参数 '1' 到 'Ipv4 make_ipv4(uint8_t, uint8_t, uint8_t, uint8_t)'
有什么提示吗?
这是“正确”的做法吗?
【问题讨论】:
【参考方案1】:语义动作中需要使用bind
懒惰绑定函数:
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
qi::uint_parser<uint8_t, 10, 1, 3> octet;
struct Ipv4Address : qi::grammar<const char *, Ipv4()>
Ipv4Address() : Ipv4Address::base_type(start)
start = ( octet >> qi::lit('.') >> octet >> qi::lit('.') >>
octet >> qi::lit('.') >> octet
) [
qi::_val = phx::bind(make_ipv4, qi::_1, qi::_2, qi::_3, qi::_4)
]
;
qi::rule<const char *, Ipv4()> start;
ipv4_address;
完整样本:
#include <string>
#include <string.h>
#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
struct Ipv4 union uint32_t as_int; uint8_t as_char[4]; raw; ;
Ipv4 make_ipv4(uint8_t i1, uint8_t i2, uint8_t i3, uint8_t i4)
Ipv4 ip;
ip.raw.as_char[0] = i1; ip.raw.as_char[1] = i2;
ip.raw.as_char[2] = i3; ip.raw.as_char[3] = i4;
return ip;
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
qi::uint_parser<uint8_t, 10, 1, 3> octet;
struct Ipv4Address : qi::grammar<const char *, Ipv4()>
Ipv4Address() : Ipv4Address::base_type(start)
start = ( octet >> qi::lit('.') >> octet >> qi::lit('.') >>
octet >> qi::lit('.') >> octet
) [
qi::_val = phx::bind(make_ipv4, qi::_1, qi::_2, qi::_3, qi::_4)
]
;
qi::rule<const char *, Ipv4()> start;
ipv4_address;
int main()
Ipv4 ip;
const char * s = "1.2.3.4";
bool r = qi::parse(s, s+strlen(s), ipv4_address, ip);
std::cout << r << " " << (int)ip.raw.as_char[0] << "." <<
(int)ip.raw.as_char[1] << "." <<
(int)ip.raw.as_char[2] << "." <<
(int)ip.raw.as_char[3] << std::endl;
【讨论】:
我怎样才能用可选的端口号修改这个优秀的例子。我正在尝试编写一个 CSV 解析器,它接受带有可选端口说明符的 ip 地址,格式为 x.y.z.w:nnnnn,其中 nnnnn 是 1-65535 范围内的小数。bool r = qi::parse(s, s+strlen(s), ipv4_address >> (":" > qi::uint_parser<uint16_t>() | qi::attr(0u)), ip, port);
会做得很好@johnco3以上是关于使用 boost-spirit 解析 ipv4 地址的主要内容,如果未能解决你的问题,请参考以下文章