2013-08-22 62 views
3

我在學習如何使用Boost.Spirit庫來解析字符串。這似乎是一個非常好的工具,但也很困難。所以,我想解析一個字符串,並用/分開一些單詞,並將它們放入一個字符串向量中。這裏是一個例子:word1/word2/word3。這是一個簡單的任務,我可以用下面的finction做到這一點:用Boost.spirit解析一個簡單的重複文本宏

bool r = phrase_parse(first, last, (+~char_("/") % qi::lit("/")),space,v) 

其中vstd::vector<std::string>。但總的來說,我想解析一下類似w1/[w2/w3]2/w4這相當於w1/w2/w3/w2/w3/w4,即[w2/w3]2意味着w2/w3重複兩次。任何人都可以給我一些想法嗎?我讀了documentation但仍有一些問題。

預先感謝您!

+0

你應該先寫下來您想要解析的格式的ebnf語法。 – PlasmaHH

+0

歡迎使用堆棧溢出。你爲這個問題選擇的標題有點模糊。 Boost.Spirit的全部目的是解析字符串。你認爲你可以編輯它,以便它更具體到*你的問題,而不是同樣適用於每一個*精神問題? –

回答

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 

(除了調試信息)

+0

通過將'_r1'別名到'in_group',使得它更具可讀性 – sehe

+0

刪除了C++ 11位,因爲它們與答案無關並且沒有真正簡化太多 – sehe

2

這是我的快速實現(C++ 11)。你可以找到很多的情況下如何解決在boost-spirit-qi各種問題和我同意的學習探索精神,需要一些努力:-)

#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("/"); 
+0

呵呵。我有點不高興'你可以進一步簡化'。 +1雖然努力。我試圖決定我喜歡哪個版本更好,你的還是我的:) – sehe

+0

@sehe我覺得我的版本對於初學者更容易:-) –

+0

可悲的是,我不能同意。我剛剛仔細檢查了一下。使用'qi :: locals',許多語義動作和'spurious'解析器提示(如' - '['')使它變得困難。此外,聖誕樹代碼佈局更難。 – sehe