3

我正在学习如何使用 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/w4which 的内容w1/w2/w3/w2/w3/w4,即[w2/w3]2重复w2/w3两次。谁能给我一些想法?我阅读了文档,但仍有一些问题。

先感谢您!

4

2 回答 2

3

完整的演示:在 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

(除了调试信息)

于 2013-08-22T21:42:20.680 回答
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("/");
于 2013-08-22T20:08:09.360 回答