【问题标题】:Right way to split an std::string into a vector<string>将 std::string 拆分为 vector<string> 的正确方法
【发布时间】:2021-07-12 12:45:58
【问题描述】:

可能重复:
How to split a string?

将字符串拆分为字符串向量的正确方法是什么。分隔符是空格或逗号。

【问题讨论】:

标签: c++ string


【解决方案1】:

这里是 roach 的解决方案的修改版本,它基于单个字符分隔符的字符串进行拆分 + 支持压缩重复分隔符的选项。

std::vector<std::string> split(std::string text, std::string delim, bool compress) 
{
    std::vector<std::string> vec;
    size_t pos = 0, prevPos = 0;
    while (1) 
    {
        pos = text.find_first_of(delim, prevPos);

        while(compress) 
        {
            if( prevPos == pos )
                prevPos++;
            else
                break;

            pos = text.find_first_of(delim, prevPos);
        }

        if (pos == std::string::npos) {
            if(prevPos != text.size())
                vec.push_back(text.substr(prevPos));
            return vec;
        }

        vec.push_back(text.substr(prevPos, pos - prevPos));
        prevPos = pos + 1;
    }
}

没有压缩的例子:

std::string s = "  1.2  foo@foo . ";
auto res = split(s, ".@ ", false);
    for(auto i : res)
        std::cout << "string {" << i << "}" << std::endl;

输出:

string {}
string {}
string {1}
string {2}
string {}
string {foo}
string {foo}
string {}
string {}

使用压缩split(s, ".@ ", true);

string {1}
string {2}
string {foo}
string {foo}

【讨论】:

    【解决方案2】:
    std::vector<std::string> split(std::string text, char delim) {
        std::string line;
        std::vector<std::string> vec;
        std::stringstream ss(text);
        while(std::getline(ss, line, delim)) {
            vec.push_back(line);
        }
        return vec;
    }
    

    split("String will be split", ' ') -> {"String", "will", "be", "split"}

    split("Hello, how are you?", ',') -> {"Hello", "how are you?"}

    编辑:这是我做的一个东西,它可以使用多字符分隔符,尽管我不能 100% 确定它是否总是有效:

    std::vector<std::string> split(std::string text, std::string delim) {
        std::vector<std::string> vec;
        size_t pos = 0, prevPos = 0;
        while (1) {
            pos = text.find(delim, prevPos);
            if (pos == std::string::npos) {
                vec.push_back(text.substr(prevPos));
                return vec;
            }
    
            vec.push_back(text.substr(prevPos, pos - prevPos));
            prevPos = pos + delim.length();
        }
    }
    

    【讨论】:

      【解决方案3】:

      我编写了这个自定义函数,这将对您有所帮助。但是要讨论时间复杂度。

      std::vector<std::string> words;
      std::string s;
      std::string separator = ",";
      
      while(s.find(separator) != std::string::npos){
         separatorIndex = s.find(separator)
         vtags.push_back(s.substr(0, separatorIndex ));
         words= s.substr(separatorIndex + 1, s.length());
      }
      
      words.push_back(s);
      
      

      【讨论】:

        【解决方案4】:

        来自Techie Delight的调整版本:

        #include <string>
        #include <vector>
        
        std::vector<std::string> split(const std::string& str, char delim) {
            std::vector<std::string> strings;
            size_t start;
            size_t end = 0;
            while ((start = str.find_first_not_of(delim, end)) != std::string::npos) {
                end = str.find(delim, start);
                strings.push_back(str.substr(start, end - start));
            }
            return strings;
        }
        

        【讨论】:

          【解决方案5】:

          对于空格分隔的字符串,你可以这样做:

          std::string s = "What is the right way to split a string into a vector of strings";
          std::stringstream ss(s);
          std::istream_iterator<std::string> begin(ss);
          std::istream_iterator<std::string> end;
          std::vector<std::string> vstrings(begin, end);
          std::copy(vstrings.begin(), vstrings.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
          

          输出:

          What
          is
          the
          right
          way
          to
          split
          a
          string
          into
          a
          vector
          of
          strings
          

          同时包含逗号和空格的字符串

          struct tokens: std::ctype<char> 
          {
              tokens(): std::ctype<char>(get_table()) {}
           
              static std::ctype_base::mask const* get_table()
              {
                  typedef std::ctype<char> cctype;
                  static const cctype::mask *const_rc= cctype::classic_table();
           
                  static cctype::mask rc[cctype::table_size];
                  std::memcpy(rc, const_rc, cctype::table_size * sizeof(cctype::mask));
           
                  rc[','] = std::ctype_base::space; 
                  rc[' '] = std::ctype_base::space; 
                  return &rc[0];
              }
          };
           
          std::string s = "right way, wrong way, correct way";
          std::stringstream ss(s);
          ss.imbue(std::locale(std::locale(), new tokens()));
          std::istream_iterator<std::string> begin(ss);
          std::istream_iterator<std::string> end;
          std::vector<std::string> vstrings(begin, end);
          std::copy(vstrings.begin(), vstrings.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
          

          输出:

          right
          way
          wrong
          way
          correct
          way
          

          【讨论】:

          • std::vector&lt;std::string&gt; vstrings(begin, end); IMO 会更好,但我想我们不知道提问者是在构建向量,还是希望填充预先存在的向量。
          • 不错,但是错了。 OP 的特殊之处在于空格和逗号都是分隔符。在这种情况下你不能做同样的伎俩,对吗?
          • 这是一个了不起的答案,需要以某种方式突出显示。
          • +1 非常好。但是您不必在某处删除在ss.imbue(std::locale(std::locale(), new tokens())) 中创建的令牌结构吗?
          • @是的,我认为阅读会做到这一点。使用auto loc = std::make_shared&lt;tokens&gt;(),然后传递ss.imbue(..., loc.get()));。那应该可以。
          【解决方案6】:

          你可以使用带分隔符的getline:

          string s, tmp; 
          stringstream ss(s);
          vector<string> words;
          
          while(getline(ss, tmp, ',')){
              words.push_back(tmp);
              .....
          }
          

          【讨论】:

            【解决方案7】:
            vector<string> split(string str, string token){
                vector<string>result;
                while(str.size()){
                    int index = str.find(token);
                    if(index!=string::npos){
                        result.push_back(str.substr(0,index));
                        str = str.substr(index+token.size());
                        if(str.size()==0)result.push_back(str);
                    }else{
                        result.push_back(str);
                        str = "";
                    }
                }
                return result;
            }
            

            split("1,2,3",",") ==> ["1","2","3"]

            split("1,2,",",") ==> ["1","2",""]

            split("1token2token3","token") ==> ["1","2","3"]

            【讨论】:

              【解决方案8】:

              我做了这个自定义函数,将线转换为矢量

              #include <iostream>
              #include <vector>
              #include <ctime>
              #include <string>
              
              using namespace std;
              
              int main(){
              
                  string line;
                  getline(cin, line);
                  int len = line.length();
                  vector<string> subArray;
              
                  for (int j = 0, k = 0; j < len; j++) {
                      if (line[j] == ' ') {
                          string ch = line.substr(k, j - k);
                          k = j+1;
                          subArray.push_back(ch);
                      }
                      if (j == len - 1) {
                          string ch = line.substr(k, j - k+1);
                          subArray.push_back(ch);
                      }
                  }
              
                  return 0;
              }
              

              【讨论】:

                【解决方案9】:

                一个方便的方法是boost's string algorithms library

                #include <boost/algorithm/string/classification.hpp> // Include boost::for is_any_of
                #include <boost/algorithm/string/split.hpp> // Include for boost::split
                // ...
                
                std::vector<std::string> words;
                std::string s;
                boost::split(words, s, boost::is_any_of(", "), boost::token_compress_on);
                

                【讨论】:

                • token_compress_on 是干什么用的?
                • @pooya13 来自文档:如果eCompress(第四个参数)设置为token_compress_on,则相邻的分隔符会合并在一起。否则,每两个分隔符分隔一个标记。 boost.org/doc/libs/1_49_0/doc/html/boost/algorithm/…
                【解决方案10】:

                如果字符串既有空格又有逗号,可以使用字符串类函数

                found_index = myString.find_first_of(delims_str, begin_index) 
                

                在一个循环中。检查 != npos 并插入向量中。如果你更喜欢老派,你也可以使用 C's

                strtok() 
                

                方法。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-01-06
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多