split関数の実装

27598 ワード

JeffChen
split関数の実装
2013年1月17日
jeffchen
2つのコメント
先日友达は私にいくつかのC++面接の問題を求めて、私はあなたが先にstringのsplit関数を書くように言って、C言語のstrtokに似ています.今、自分のコードの中で、split関数の実現は本当に興味津々で、どんな方法でどんな方法を使うかを考えてみましょう.
1つの方法はstringstreamを使用し、getlineを使用することです.
void split(const std::string &s, char delim, std::vector<std::string> &elems) {
    std::stringstream ss(s);
    std::string item;
    while(std::getline(ss, item, delim)) {
        elems.push_back(item);
    }
}

regexで実装することもできます.
void split(const string &s,const string &delim,vector<string>&elems){
	regex reg(delim);
	sregex_token_iterator it(s.begin(),s.end(),reg,-1);
	sregex_token_iterator end;
	while (it!=end)
	{
		elems.push_back(*it++);
	}
}

そしてstackoverflowに行ってsearchをしましたが、この問題は意外にも上のC++tag問題で上位にランクインしました!さまざまなカスタムtemplate実装をサポートします.
template < class ContainerT >
void tokenize(const std::string& str, ContainerT& tokens,
              const std::string& delimiters = " ", const bool trimEmpty = false)
{
   std::string::size_type pos, lastPos = 0;
   while(true)
   {
      pos = str.find_first_of(delimiters, lastPos);
      if(pos == std::string::npos)
      {
         pos = str.length();
 
         if(pos != lastPos || !trimEmpty)
            tokens.push_back(ContainerT::value_type(str.data()+lastPos,
                  (ContainerT::value_type::size_type)pos-lastPos ));
         break;
      }
      else
      {
         if(pos != lastPos || !trimEmpty)
            tokens.push_back(ContainerT::value_type(str.data()+lastPos,
                  (ContainerT::value_type::size_type)pos-lastPos ));
      }
      lastPos = pos + 1;
   }
};

stringで提供されるfind of関数を使用して実現します.
void Tokenize(const string& str,
                      vector<string>& tokens,
                      const string& delimiters = " ")
{
    // Skip delimiters at beginning.
    string::size_type lastPos = str.find_first_not_of(delimiters, 0);
    // Find first "non-delimiter".
    string::size_type pos     = str.find_first_of(delimiters, lastPos);
 
    while (string::npos != pos || string::npos != lastPos)
    {
        // Found a token, add it to the vector.
        tokens.push_back(str.substr(lastPos, pos - lastPos));
        // Skip delimiters.  Note the "not_of"
        lastPos = str.find_first_not_of(delimiters, pos);
        // Find next "non-delimiter"
        pos = str.find_first_of(delimiters, lastPos);
    }
}

スペースで分離する場合は、より簡潔な方法があります.
void split(const string &s,const string &delim,vector<string>&elems){
    string buf;
    stringstream ss(s); 
    while (ss >> buf)
        elems.push_back(buf);
}

JeffChen»split関数の実装
split関数の実装
2013年1月17日
jeffchen
コメント
コメントを読む
先日友达は私にいくつかのC++面接の問題を求めて、私はあなたが先にstringのsplit関数を書くように言って、C言語のstrtokに似ています.今、自分のコードの中で、split関数の実現は本当に興味津々で、どんな方法でどんな方法を使うかを考えてみましょう.
1つの方法はstringstreamを使用し、getlineを使用することです.
void split(const std::string &s, char delim, std::vector<std::string> &elems) {
    std::stringstream ss(s);
    std::string item;
    while(std::getline(ss, item, delim)) {
        elems.push_back(item);
    }
}

regexで実装することもできます.
void split(const string &s,const string &delim,vector<string>&elems){
	regex reg(delim);
	sregex_token_iterator it(s.begin(),s.end(),reg,-1);
	sregex_token_iterator end;
	while (it!=end)
	{
		elems.push_back(*it++);
	}
}

そしてstackoverflowに行ってsearchをしましたが、この問題は意外にも上のC++tag問題で上位にランクインしました!さまざまなカスタムtemplate実装をサポートします.
template < class ContainerT >
void tokenize(const std::string& str, ContainerT& tokens,
              const std::string& delimiters = " ", const bool trimEmpty = false)
{
   std::string::size_type pos, lastPos = 0;
   while(true)
   {
      pos = str.find_first_of(delimiters, lastPos);
      if(pos == std::string::npos)
      {
         pos = str.length();
 
         if(pos != lastPos || !trimEmpty)
            tokens.push_back(ContainerT::value_type(str.data()+lastPos,
                  (ContainerT::value_type::size_type)pos-lastPos ));
         break;
      }
      else
      {
         if(pos != lastPos || !trimEmpty)
            tokens.push_back(ContainerT::value_type(str.data()+lastPos,
                  (ContainerT::value_type::size_type)pos-lastPos ));
      }
      lastPos = pos + 1;
   }
};

stringで提供されるfind of関数を使用して実現します.
void Tokenize(const string& str,
                      vector<string>& tokens,
                      const string& delimiters = " ")
{
    // Skip delimiters at beginning.
    string::size_type lastPos = str.find_first_not_of(delimiters, 0);
    // Find first "non-delimiter".
    string::size_type pos     = str.find_first_of(delimiters, lastPos);
 
    while (string::npos != pos || string::npos != lastPos)
    {
        // Found a token, add it to the vector.
        tokens.push_back(str.substr(lastPos, pos - lastPos));
        // Skip delimiters.  Note the "not_of"
        lastPos = str.find_first_not_of(delimiters, pos);
        // Find next "non-delimiter"
        pos = str.find_first_of(delimiters, lastPos);
    }
}

スペースで分離する場合は、より簡潔な方法があります.
void split(const string &s,const string &delim,vector<string>&elems){
    string buf;
    stringstream ss(s); 
    while (ss >> buf)
        elems.push_back(buf);
}