首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何为boost::tokenizer实现tokenizer.rbegin()和rend()?

如何为boost::tokenizer实现tokenizer.rbegin()和rend()?
EN

Stack Overflow用户
提问于 2011-01-05 22:30:10
回答 3查看 1.4K关注 0票数 3

我在玩boost::tokenizer,但是我意识到它不支持rbegin()和rend()。我想问一下,如何将这两个函数添加到现有的类中?

这是来自boost站点的:

代码语言:javascript
复制
#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:

代码语言:javascript
复制
//===========================================================================
  // 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_;
  };

然后,我将重点讨论这两种方法:

代码语言:javascript
复制
iter begin() const { return iter(f_,first_,last_); }
iter end() const { return iter(f_,last_,last_); }

由于它返回一个类型为iter( f_、first_、last_ )的构造函数,所以我将移到这个类的源代码。而iter实际上是:

代码语言:javascript
复制
 typedef typename TGen::type iter;

这是token_iterator_generator类。这个类的实现是:

代码语言:javascript
复制
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的实现真的把我吓坏了:

代码语言:javascript
复制
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<>的遗传部分是如此复杂。知道我该下一个去吗?

谢谢,

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-01-06 00:46:18

当然,您可以创建一个新的类来实现这一点,只需使用普通的令牌程序迭代字符串,并将值存储在向量中。然后使用向量实现rend和vector。

虽然在运行时内存强度可能不是最快的,但出错的风险很小,而且很简单。除非您知道这将是一个问题,这是我将采取的路线,因为它是非常容易和快速实现。

但是,您特别要求扩展现有的类,我认为这是个坏主意。在本例中,最简单的方法可能是修改构造函数,该构造函数接受容器(您正在使用的容器)实例化内部令牌程序对象,使用的是rbegin()和rend(),而不是容器的begin()和end()。要实现您自己的rbegin()和rend(),首先从从内部令牌程序获得的迭代器开始。不过,从这些标记返回的令牌可能是向后的,因此您需要将其反转。但是,使用boost::iterator包很容易实现实际的迭代器类型。

请注意,您需要特别注意使用显式迭代器的构造函数,或者只决定为反向迭代器实现类功能的一个子集(在这种情况下,您可能应该使用一个单独的类来保存两个内部标记器,而不是假装是一个助推::tokenizer)。

替代方法是修改char_separator (和其他分隔符类),以便显式地指定tokenizer_detail::assign_or_plus_equal的哪个专门化,这样就可以在每个部分字符串的开头而不是末尾添加每个字符。

希望这能有所帮助。我会选择第一种选择,或者只是简单地改变我的需求,这样我就不需要反向迭代器了。

票数 1
EN

Stack Overflow用户

发布于 2011-01-06 00:29:59

考虑到这一点(来自文献资料)

tokenizer类提供了包含在序列中的一系列令牌的容器视图。您可以设置要解析的序列和用于在构造时或使用分配成员函数解析序列的TokenizerFunction。注意:在构造时不实际进行解析。解析是根据需要完成的,因为令牌是通过begin提供的迭代器访问的。

我认为您几乎可以复制粘贴代码,但是从str(Str)-1开始,一直到0。但是,您首先必须创建一个名为reverse_iterator的ty胡枝子,并在反向迭代器到达字符串的开头时,根据需要真正解析这些令牌。不要犹豫,展示你的进步,并在你做的时候提出问题。

票数 0
EN

Stack Overflow用户

发布于 2011-06-06 18:39:53

我建议使用增强::算法::拆分

代码语言:javascript
复制
#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字符串算法库)

因此,您可以轻松地使用rbegin()和rend()来迭代生成的std::vector。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4609861

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档