2011-01-05 8 views
3

私はboost :: tokenizerで遊んでいますが、rbegin()とrend()はサポートしていません。これらの2つの機能を既存のクラスに追加するにはどうすればいいですか?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; 
} 

更新
これは私の現在の進行状況です。 Iは、トークナイザの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_; 
    }; 

そして私は2つの方法に焦点を当てて:それはタイプITERのコンストラクタを返すので(F_、first_in_sequenceが、last_)

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

、Iは次に移動このクラスのソースにiterは実際には:

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; 
    }; 

今私は>トークナイザクラスのイテレータが< 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

もちろん、通常のトークナイザを使って文字列を繰り返し、その値をベクトルに格納するだけで、これを実装する新しいクラスを作成できます。次に、ベクトルを使ってrendとrbeginを実装します。

実行時におそらく最も高速でメモリの消費量が最小ではないにもかかわらず、エラーが発生するリスクはごくわずかです。これが問題になることがわかっていない限り、これは非常に簡単で実装が速いので、私が取るルートです。

あなたは具体的に既存のクラスを拡張するように依頼しますが、これは悪い考えです。この場合、コンテナのbegin()とend()の代わりにrbegin()とrend()を使用して内部トークナイザオブジェクトをインスタンス化するコンテナ(使用しているコンストラクタ)を使用するコンストラクタを変更するのが最も簡単です。独自のrbegin()とrend()をインプリメントするには、内部トークナイザから開始して終了するイテレータから始めます。これらから返されたトークンはおそらく後ろ向きになるでしょうから、それらを逆にする必要があります。実際のイテレータの型は、おそらくboost :: iteratorsパッケージを使って実装するのはかなり簡単でしょう。

明示的なイテレータを取るコンストラクタには特別な注意が必要であることに注意してください。リバースイテレータのクラスの機能のサブセットを実装することだけを決定する必要があります。とにかくboost :: tokenizerの代わりに2つの内部トークナイザ)。

char_separator(およびその他のセパレータクラス)を変更してtokenizer_detail :: assign_or_plus_equalの特殊化を明示的に指定できるようにすることで、各文字列を各部分文字列の先頭に追加することができます終わり。

これが役に立ちます。私は最初の選択肢に行くか、単に逆の反復子が必要ないように自分の要件を変更するだけです。

0

これを考慮した(the documentationから)

トークナイザクラスはコンタを提供シークエンスに含まれる一連のトークンのインナービュー。構文解析するシーケンスを設定し、TokenizerFunctionを使用して構築時またはassignメンバー関数を使用してシーケンスを解析します。注:実際には構文解析は行われません。 beginによって提供されるイテレータを介してトークンにアクセスするので、解析はオンデマンドで行われます。私はあなたがほとんどのコードをコピー&ペーストすることができますと言うだろうが、[STRLEN(文字列)-1]と0まで行くSTRから始まることはしかし、あなたが最初に本当にreverse_iteratorという名前のtypedefを作成する必要がありますし、

逆のイテレータが文字列の先頭に移動すると、必要に応じてトークンを解析します。あなたの進捗状況を示すことを躊躇しないで、あなたがそれをしている間に質問をしてください。

0

私はあなたが簡単に(rbeginと結果のstd ::ベクトル(を反復)と引き裂くことができ

Boost String Algorithms Libraryを参照))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("/")); 

を使用することをお勧めします。

関連する問題