我正在学习如何使用Boost.Spirit库来解析字符串。它似乎是一个非常好的工具,但也很难。所以,我想用一些用/
分隔的单词解析一个字符串,并将它们放在一个字符串向量中。以下是一个示例:word1/word2/word3
。这是一项简单的任务,我可以通过以下方式完成此任务:
bool r = phrase_parse(first, last, (+~char_("/") % qi::lit("/")),space,v)
其中v
为std::vector<std::string>
。但总的来说,我想解析w1/[w2/w3]2/w4
等同于w1/w2/w3/w2/w3/w4
的内容,即[w2/w3]2
意味着w2/w3
重复两次。有人能给我一些想法吗?我读了documentation但仍有一些问题。
提前谢谢!
答案 0 :(得分:3)
完全正常工作的演示: live on Coliru
如果状态为raw
,那么通过简单方法添加的]
值可选择在in_group
结束。
我选择使用继承的属性(bool
)传递状态。
此实现也允许嵌套子组,例如:"[w1/[w2/w3]2/w4]3"
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace phx = boost::phoenix;
int main()
{
typedef std::string::const_iterator It;
const std::string input = "[w1/[w2/w3]2/w4]3";
std::vector<std::string> v;
It first(input.begin()), last(input.end());
using namespace boost::spirit::qi;
rule<It, std::string(bool in_group)> raw;
rule<It, std::vector<std::string>(bool in_group), space_type>
group,
delimited;
_r1_type in_group; // friendly alias for the inherited attribute
raw = eps(in_group) >> +~char_("/]")
| +~char_("/");
delimited = (group(in_group)|raw(in_group)) % '/';
group = ('[' >> delimited(in_group=true) >> ']' >> int_)
[ phx::while_(_2--)
[ phx::insert(_val, phx::end(_val), phx::begin(_1), phx::end(_1)) ]
];
BOOST_SPIRIT_DEBUG_NODES((raw)(delimited)(group));
bool r = phrase_parse(first, last,
delimited(false),
space,v);
if (r)
std::copy(v.begin(), v.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
}
打印:
w1
w2
w3
w2
w3
w4
w1
w2
w3
w2
w3
w4
w1
w2
w3
w2
w3
w4
(除了调试信息)
答案 1 :(得分:2)
这是我的快速实现(c ++ 11)。您可以在boost-spirit-qi中找到解决各种问题的大量场景,我同意学习SPIRIT需要付出一些努力: - )
#define BOOST_RESULT_OF_USE_DECLTYPE
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <string>
struct SInsert
{
struct result
{
typedef void type;
};
void operator()( std::vector<std::string>&out,
std::vector<std::string>&in, int counter ) const
{
for( int i=0; i<counter; ++i )
std::copy( in.begin(), in.end(), std::back_inserter(out) );
}
};
boost::phoenix::function<SInsert> inserter;
int main()
{
namespace qi = boost::spirit::qi;
namespace ph = boost::phoenix;
namespace ascii = boost::spirit::ascii;
for ( auto &str : std::vector< std::string >
{ "w1/ w2 /w4 ",
"[w2]1 /w4 ",
"[w2/w3]2 /w4 ",
"[]0",
"[]0 / w4"
}
)
{
std::cout << "input:" << str << std::endl;
std::string::const_iterator iter( str.begin() );
std::string::const_iterator last( str.end() );
std::vector< std::string > v;
qi::rule<std::string::const_iterator,
qi::locals< std::vector<std::string> >,
ascii::space_type ,std::vector<std::string>()> mrule =
( qi::as_string[ qi::lexeme[ +(qi::graph -"/"-"[") ] ][ ph::push_back( qi::_val,qi::_1 )] |
(
qi::lit("[")
>> -(
qi::eps[ ph::clear( qi::_a ) ]
>> qi::as_string[ qi::lexeme[ +(qi::graph-"/"-"]") ] ][ ph::push_back( qi::_a ,qi::_1 ) ]
% qi::lit("/")
)
)
>> qi::lit("]" )
>> qi::int_[ inserter( qi::_val,qi::_a,qi::_1 ) ]
)
% qi::lit("/");
if( qi::phrase_parse( iter, last, mrule , ascii::space, v ) && iter==last )
std::copy( v.begin(), v.end(),
std::ostream_iterator<std::string>( std::cout,"\n" ));
else
std::cerr << "parsing failed:" << *iter << std::endl;
}
return 0;
}
您可以进一步简化mrule
,以便自动合成属性而不是使用语义操作 - 即使您不会完全避免它们:
qi::rule<std::string::const_iterator,
qi::locals< std::vector<std::string> >,
ascii::space_type ,std::vector<std::string>()> mrule;
mrule %=
(
qi::as_string[ qi::lexeme[ +(qi::graph -"/"-"[") ] ] |
qi::lit("[")
>> -(
qi::eps[ ph::clear( qi::_a ) ]
>> qi::as_string[ qi::lexeme[ +(qi::graph-"/"-"]") ] ][ ph::push_back( qi::_a ,qi::_1 ) ]
% qi::lit("/")
)
>> qi::lit("]" )
>> qi::omit[ qi::int_[ inserter( qi::_val,qi::_a,qi::_1-1 ) ] ]
)
% qi::lit("/");
由于sehe
指向一些丑陋的结构,这里是一个小的简化:
qi::rule<std::string::const_iterator,
qi::locals< std::vector<std::string> >,
ascii::space_type ,std::vector<std::string>()> mrule;
mrule %= (
qi::as_string[ qi::lexeme[ +qi::alnum ] ] |
qi::lit("[")
>> -(
qi::eps[ ph::clear( qi::_a ) ] >>
qi::as_string[ qi::lexeme[ +qi::alnum ] ][ ph::push_back( qi::_a ,qi::_1 ) ]
% qi::lit("/")
)
>> qi::lit("]")
>> qi::omit[ qi::int_[ inserter( qi::_val,qi::_a,qi::_1-1 ) ] ]
) % qi::lit("/");