2011-01-05 55 views
3

我在玩boost :: tokenizer,但是我意識到它不支持rbegin()和rend()。我想問一下如何將這兩個函數添加到現有類中?如何爲boost :: tokenizer實現tokenizer.rbegin()和rend()?

這是從提升網站:

#include <iostream> 
#include <string> 
#include <boost/tokenizer.hpp> 

using namespace std; 
using namespace boost; 

int main() { 
string str("12/12/1986"); 
typedef boost::tokenizer<boost::char_separator<char>> tokenizer; 
boost::char_separator<char> sep("/"); 
tokenizer tokens(str, sep); 
cout << *tokens.begin() << endl; 
    // cout << *tokens.rbegin() << endl; How could I implement this? 
return 0; 
} 

更新
這是我目前的進展。我首先導航到標記生成器的src:

//=========================================================================== 
    // A container-view of a tokenized "sequence" 
    template < 
    typename TokenizerFunc = char_delimiters_separator<char>, 
    typename Iterator = std::string::const_iterator, 
    typename Type = std::string 
    > 
    class tokenizer { 
    private: 
    typedef token_iterator_generator<TokenizerFunc,Iterator,Type> TGen; 

    // It seems that MSVC does not like the unqualified use of iterator, 
    // Thus we use iter internally when it is used unqualified and 
    // the users of this class will always qualify iterator.  
    typedef typename TGen::type iter; 

    public: 

    typedef iter iterator; 
    typedef iter const_iterator; 
    typedef Type value_type; 
    typedef value_type& reference; 
    typedef const value_type& const_reference; 
    typedef value_type* pointer; 
    typedef const pointer const_pointer; 
    typedef void size_type; 
    typedef void difference_type; 

    tokenizer(Iterator first, Iterator last, 
       const TokenizerFunc& f = TokenizerFunc()) 
     : first_(first), last_(last), f_(f) { } 

    template <typename Container> 
    tokenizer(const Container& c) 
     : first_(c.begin()), last_(c.end()), f_() { } 

    template <typename Container> 
    tokenizer(const Container& c,const TokenizerFunc& f) 
     : first_(c.begin()), last_(c.end()), f_(f) { } 

    void assign(Iterator first, Iterator last){ 
     first_ = first; 
     last_ = last; 
    } 

    void assign(Iterator first, Iterator last, const TokenizerFunc& f){ 
     assign(first,last); 
     f_ = f; 
    } 

    template <typename Container> 
    void assign(const Container& c){ 
     assign(c.begin(),c.end()); 
    } 


    template <typename Container> 
    void assign(const Container& c, const TokenizerFunc& f){ 
     assign(c.begin(),c.end(),f); 
    } 

    iter begin() const { return iter(f_,first_,last_); } 
    iter end() const { return iter(f_,last_,last_); } 

    private: 
    Iterator first_; 
    Iterator last_; 
    TokenizerFunc f_; 
    }; 

然後我集中在兩種方法:

iter begin() const { return iter(f_,first_,last_); } 
iter end() const { return iter(f_,last_,last_); } 

因爲它返回類型ITER的一個構造(F_,first_,last_),I然後移動到這個班的來源。而且它實際上是:

typedef typename TGen::type iter; 

它是token_iterator_generator類。而這一類的實現是:

template < 
     class TokenizerFunc = char_delimiters_separator<char>, 
     class Iterator = std::string::const_iterator, 
     class Type = std::string 
    > 
    class token_iterator_generator { 

    private: 
    public: 
     typedef token_iterator<TokenizerFunc,Iterator,Type> type; 
    }; 

所以現在我想通了,tokenizer類的迭代器實際上是token_iterator <>。而token_iterator的實現真的把我嚇壞了:

template <class TokenizerFunc, class Iterator, class Type> 
    class token_iterator 
     : public iterator_facade< 
      token_iterator<TokenizerFunc, Iterator, Type> 
      , Type 
      , typename detail::minimum_category< 
       forward_traversal_tag 
       , typename iterator_traversal<Iterator>::type 
      >::type 
      , const Type& 
     > 
    { 

     friend class iterator_core_access; 

     TokenizerFunc f_; 
     Iterator begin_; 
     Iterator end_; 
     bool valid_; 
     Type tok_; 

     void increment(){ 
      BOOST_ASSERT(valid_); 
      valid_ = f_(begin_,end_,tok_); 
     } 

     const Type& dereference() const { 
      BOOST_ASSERT(valid_); 
      return tok_; 
     } 
     template<class Other> 
     bool equal(const Other& a) const{ 
      return (a.valid_ && valid_) 
       ?((a.begin_==begin_) && (a.end_ == end_)) 
       :(a.valid_==valid_); 

     } 

     void initialize(){ 
      if(valid_) return; 
      f_.reset(); 
      valid_ = (begin_ != end_)? 
       f_(begin_,end_,tok_):false; 
     } 
    public: 
     token_iterator():begin_(),end_(),valid_(false),tok_() { } 

     token_iterator(TokenizerFunc f, Iterator begin, Iterator e = Iterator()) 
      : f_(f),begin_(begin),end_(e),valid_(false),tok_(){ initialize(); } 

     token_iterator(Iterator begin, Iterator e = Iterator()) 
      : f_(),begin_(begin),end_(e),valid_(false),tok_() {initialize();} 

     template<class OtherIter> 
     token_iterator(
      token_iterator<TokenizerFunc, OtherIter,Type> const& t 
      , typename enable_if_convertible<OtherIter, Iterator>::type* = 0) 
      : f_(t.tokenizer_function()),begin_(t.base()) 
      ,end_(t.end()),valid_(!t.at_end()),tok_(t.current_token()) {} 

     Iterator base()const{return begin_;} 

     Iterator end()const{return end_;}; 

     TokenizerFunc tokenizer_function()const{return f_;} 

     Type current_token()const{return tok_;} 

     bool at_end()const{return !valid_;} 




    }; 

這個類是非常複雜的,而且我在這裏失去了:(繼承部分來自iterator_facade <>太複雜 任何想法,我應該去下!?

謝謝,

回答

1

你當然可以創建一個新的類來實現這一點,只需使用普通標記器迭代字符串並將值存儲在向量中即可。然後使用vector實現rend和rbegin。

發生錯誤的風險很小,但運行時可能不是最快也不是最少的內存密集。除非你知道這將會成爲一個問題,否則這是我會採用的路線,因爲它的實施非常簡單快捷。

然而,你特別要求擴展現有的類,我認爲這是一個壞主意。在這種情況下,最簡單的方法可能是改變構造函數,使用容器(您正在使用的容器)使用rbegin()和rend()而不是begin()和end()來實例化內部標記器對象。爲了實現你自己的rbegin()和rend(),從你從內部標記器開始和結束的迭代器開始。從這些返回的令牌可能會後退,所以您需要將這些令牌取消。但實際的迭代器類型可能很容易使用boost :: iterators包來實現。

請注意,您需要特別注意帶有顯式迭代器的構造函數,或者只決定爲您的反向迭代器實現類的功能子集(在這種情況下,您應該使用一個單獨的類來保持兩個內部標記器無論如何不是假裝成boost :: tokenizer)。

這另一種方法是改變char_separator(和另一個分離裝置類),這樣就可以明確指定的:: assign_or_plus_equal,這樣就可以在每個部分字符串的開頭添加的每個字符,而不是tokenizer_detail的專業化哪結束。

希望這會有所幫助。我會選擇第一個選擇,或者只是簡單地改變我的需求,這樣我就不需要反向迭代器了。

0

考慮到這一點(從the documentation

記號賦予類提供一個CONTA包含在序列中的一系列令牌的視圖。您可以將序列設置爲解析,並使用TokenizerFunction在構造或使用assign成員函數時解析序列。注意:沒有解析實際上是在構建過程中完成的。解析是按需完成的,因爲令牌是通過begin提供的迭代器訪問的。

我說你幾乎可以複製粘貼代碼,但在海峽開始[strlen的(STR)-1]中去,直到0。但是,你首先要創建一個名爲reverse_iterator的typedef的真的當逆向迭代器進入字符串的開始時,按需解析標記。不要猶豫,以顯示你的進步,並提出問題,而你這樣做。

0

我會建議使用boost::algorithm::split

#include <boost/algorithm/string/split.hpp> 

std::string str("12/12/1986"); 
std::vector<std::string> results; 

boost::algorithm::split(results, str, boost::algorithm::is_any_of("/")); 

(見Boost String Algorithms Library

所以,你可以很容易地遍歷產生的std ::用rbegin向量()和雷德()。