【问题标题】:Split string by a character? [duplicate]按字符拆分字符串? [复制]
【发布时间】:2014-01-12 08:33:42
【问题描述】:

如何通过":" 字符拆分"102:330:3133:76531:451:000:12:44412 等字符串,并将所有数字放入一个int 数组(数字序列始终为8 个元素长)?最好不要使用诸如 boost 之类的外部库。

另外,我想知道如何在字符串处理之前从字符串中删除不需要的字符,例如“$”和“#”?

【问题讨论】:

  • @CaptainObvlious 这不是一个充分的评论 - 请指定您正在使用的 elven magic 的版本
  • @johny 几乎是同一个问题,但是我猜 OP 也不知道如何从字符串转换为数字。
  • 好的老strtok怎么样?

标签: c++ arrays string split tokenize


【解决方案1】:

C 中的标准方法是使用strtok,就像其他人回答的那样。然而strtok 不是C++-like 和unsafe。 C++ 中的标准方式是使用std::istringstream

std::istringstream iss(str);
char c; // dummy character for the colon
int a[8];
iss >> a[0];
for (int i = 1; i < 8; i++)
    iss >> c >> a[i];

如果输入总是有固定数量的这样的标记,sscanf 可能是另一个简单的解决方案

std::sscanf(str, "%d:%d:%d:%d:%d:%d:%d:%d", &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8);

【讨论】:

    【解决方案2】:

    stringstream 可以做到所有这些。

    1. 拆分一个字符串并存储到 int 数组中:

      string str = "102:330:3133:76531:451:000:12:44412";
      std::replace(str.begin(), str.end(), ':', ' ');  // replace ':' by ' '
      
      vector<int> array;
      stringstream ss(str);
      int temp;
      while (ss >> temp)
          array.push_back(temp); // done! now array={102,330,3133,76531,451,000,12,44412}
      
    2. 在处理之前从字符串中删除不需要的字符,例如$#:就像上面处理:的方式一样。

    PS:上述解决方案仅适用于不包含空格的字符串。处理带空格的字符串,请参考here基于std::string::find()std::string::substr()

    【讨论】:

    • 当我尝试你的代码时,我得到了这些错误:(没有操作符“==”匹配这些操作数操作数类型是:char == const char [2])(类型为“const char * " 不能分配给类型为 "char" 的实体)
    • @user2705775 已修复。 :)
    • 不用手动替换冒号,只需使用std::replace(str.begin(), str.end(), ':', ' ');
    • 这是一个非常具体的答案,如果字符串包含空格则不起作用。
    • @MartinMassera 感谢您指出这一点。更新答案以整合它。谢谢。
    【解决方案3】:
    #include <stdio.h>
    #include <string.h>
    
    int main ()
    {
      char str[] ="102:330:3133:76531:451:000:12:44412";
      char * pch;
      printf ("Splitting string \"%s\" into tokens:\n",str);
      pch = strtok (str,":");
      while (pch != NULL)
      {
        printf ("%s\n",pch);
        pch = strtok (NULL, ":");
      }
      return 0;
    }
    

    【讨论】:

      【解决方案4】:

      要删除字符“#”和“$”,您可以使用标准算法std::remove_if。但是请注意,如果有例如以下字符串“12#34”,那么在删除“#”之后,您将得到“1234”。如果您需要结果字符串看起来像“12 34”或“12:34”,那么最好使用std::remove_if,而不是std::replace_if

      下面是执行任务的示例代码。您需要包含标题

      #include <iostream>
      #include <cstdlib>
      #include <cstring>
      #include <algorithm>
      
      int main()
      {
          char s[] = "102:$$330:#3133:76531:451:000:$12:44412";
      
          std::cout << s << std::endl;
      
          char *p = std::remove_if( s, s + std::strlen( s ), 
              []( char c ) { return ( c == '$' || c == '#' ); } );
          *p = '\0';
      
          std::cout << s << std::endl;
      
          const size_t N = 8;
          int a[N];
      
          p = s;
          for ( size_t i = 0; i < N; i++ )
          {
              a[i] = strtol( p, &p, 10 );
              if ( *p == ':' ) ++p;
          }
      
          for ( int x : a ) std::cout << x << ' ';
          std::cout << std::endl;
      }
      

      输出是

      102:$$330:#3133:76531:451:000:$12:44412
      102:330:3133:76531:451:000:12:44412
      102 330 3133 76531 451 0 12 44412
      

      【讨论】:

        【解决方案5】:

        使用 C++11 中正则表达式功能的另一种解决方案。

        #include <algorithm>
        #include <iostream>
        #include <iterator>
        #include <ostream>
        #include <regex>
        #include <sstream>
        #include <string>
        #include <vector>
        
        int main()
        {
            const std::string s = "102:330:3133:76531:451:000:12:44412";
        
            // Replace each colon with a single space
            const std::regex pattern(":");
            const std::string r = std::regex_replace(s, pattern, " ");
        
            std::istringstream ist(r);
        
            std::vector<int> numbers;
            std::copy(std::istream_iterator<int>(ist), std::istream_iterator<int>(),
                std::back_inserter(numbers));
        
            // We now have a vector of numbers
        
            // Print it out
            for (auto n : numbers)
            {
                std::cout << n << " ";
            }
            std::cout << std::endl;
        
            return 0;
        }
        

        【讨论】:

          【解决方案6】:

          我之前不得不写一些这样的代码,并在 Stack Overflow 上发现了一个关于通过分隔符拆分字符串的问题。这是原始问题:link

          您可以将它与std::stoi 一起使用来构建向量。

          std::vector<int> split(const std::string &s, char delim) {
              std::vector<int> elems;
              std::stringstream ss(s);
              std::string number;
              while(std::getline(ss, number, delim)) {
                  elems.push_back(std::stoi(number));
              }
              return elems;
          }
          
          // use with:
          const std::string numbers("102:330:3133:76531:451:000:12:44412");
          std::vector<int> numbers = split(numbers, ':');
          

          Here is a working ideone sample.

          【讨论】:

          • 有没有一种简单的方法可以将其存储在数组中而不是向量中?
          • @user2705775 std::copy(vector.begin(), vector.end(), std::begin(array)).
          • @user2705775 将其存储在数组中的问题在于,在完全解析字符串之前,您似乎不知道字符数。如果你真的需要,你可以选择什么 remyabel,但我不太明白这一点。
          【解决方案7】:

          真的!没有elven magic

          也有人回答here

          #include <cstring>
          #include <iostream>
          #include<cstdlib>
          #include<vector>
          
          int main() 
          {
              char input[100] = "102:330:3133:76531:451:000:12:44412";
              char *token = std::strtok(input, ":");
              std::vector<int> v;
          
              while (token != NULL) {
                  v.push_back( std::strtol( token, NULL, 10 ));
                  token = std::strtok(NULL, ":");
              }
          
              for(std::size_t i =0 ; i < v.size() ; ++i)
                  std::cout << v[i] <<std::endl;
          }
          

          演示Here

          【讨论】:

            【解决方案8】:

            你可以使用strtok() 来分割你的字符串,也许在while循环中。

            当您获得单个字符串时,可以使用atoi(xxx) 进行整数转换。

            【讨论】:

            【解决方案9】:

            这是一种方法……虽然不是最聪明但写起来很快(8 次重复几乎可以保证循环)。这种解析方法非常有用,非常好学。 !(iss &gt;&gt; c) 确保字符串中没有尾随的非空白字符。

            std::istringstream iss(the_string);
            char c;
            int n[8];
            if (iss >> n[0] >> c && c == ':' &&
                iss >> n[1] >> c && c == ':' &&
                iss >> n[2] >> c && c == ':' &&
                iss >> n[3] >> c && c == ':' &&
                iss >> n[4] >> c && c == ':' &&
                iss >> n[5] >> c && c == ':' &&
                iss >> n[6] >> c && c == ':' &&
                iss >> n[7] && !(iss >> c))
                ...
            

            【讨论】:

            • 为什么还要检查c == ':'
            • @Beta:通常认为检查输入是否符合预期是一种合理的做法……如果缺少冒号,则可能意味着输入还有其他虚假内容。例如,如果有人通过“3.14 12.78 999.1 38.6”,否则它将解析为[ 3 14 2 78 99 1 8 6 ]。 (我真的厌倦了看到如果人们正确检查输入和输出就会发现 I/O 问题的 S.O. 问题。
            • 我收到一个错误“no operator ">>" 匹配这些操作数。操作数类型是:std::istringstream >> int"
            • @user2705775:你#include &lt;sstream&gt;了吗?
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-04-20
            • 2020-10-03
            • 2012-11-08
            • 1970-01-01
            • 2011-03-03
            相关资源
            最近更新 更多