【问题标题】:Is There A Built-In Way to Split Strings In C++?有没有内置的方法在 C++ 中拆分字符串?
【发布时间】:2010-10-10 15:25:52
【问题描述】:

嗯,有吗?字符串我的意思是 std::string

【问题讨论】:

  • 尽管我很喜欢 C++,但我仍然讨厌绕着它的弦走。
  • 啊对。看起来像一个重复的问题。我建议关闭这个然后将人们重定向到另一个“c-how-to-split-a-string”。你觉得呢?
  • 嗯,我只是在阅读另一个问题,允许在字符串中有空格。也许那时不应该关闭这个。不确定了:)
  • 下面的一些示例怎么样:codeproject.com/KB/recipes/Tokenizer.aspx 它们非常高效且有些优雅。字符串工具包库使 C++ 中的复杂字符串处理变得简单易行。

标签: c++ string split


【解决方案1】:

C 字符串

只需在要拆分的位置插入\0。这与标准 C 函数一样内置。

此函数在第一次出现char 分隔符时进行拆分,返回第二个字符串。

char *split_string(char *str, char separator) {
    char *second = strchr(str, separator);
    if(second == NULL)
        return NULL;

    *second = '\0';
    ++second;
    return second;
}

【讨论】:

  • @cdonner,因为 strchr 更简单。 =]
  • @strager:这是一个糟糕的设计——修改输入。虽然这是 strtok() 一直在做的事情并且已经逃脱了。
  • @dirkgently,嗯,我将 strtok 误读为带有多个分隔符的 strchr。对功能了解不多。我的错......另外,我不会说这是糟糕的设计。如果记录得当,IMO 会很清楚。
  • strtok 不可重入。但是,使用类似 strtok 的工具是完全合理的,该工具首先将输入字符串复制到自己的缓冲区中,以避免修改输入或全局状态。
  • @epochwolf,在发布此内容时,原始问题并未提及 C 字符串或 std::string。
【解决方案2】:

答案是否定的。您必须使用其中一个库函数将它们分解。

我用的东西:

std::vector<std::string> parse(std::string l, char delim) 
{
    std::replace(l.begin(), l.end(), delim, ' ');
    std::istringstream stm(l);
    std::vector<std::string> tokens;
    for (;;) {
        std::string word;
        if (!(stm >> word)) break;
        tokens.push_back(word);
    }
    return tokens;
}

你也可以看看basic_streambuf&lt;T&gt;::underflow()方法,写一个过滤器。

【讨论】:

    【解决方案3】:

    STL 字符串

    你可以使用字符串迭代器来做你的脏活。

    std::string str = "hello world";
    
    std::string::const_iterator pos = std::find(string.begin(), string.end(), ' '); // Split at ' '.
    
    std::string left(str.begin(), pos);
    std::string right(pos + 1, str.end());
    
    // Echoes "hello|world".
    std::cout << left << "|" << right << std::endl;
    

    【讨论】:

    • 那么这是否仅适用于两个单词的字符串??
    【解决方案4】:
    void split(string StringToSplit, string Separators)
    {
        size_t EndPart1 = StringToSplit.find_first_of(Separators)
        string Part1 = StringToSplit.substr(0, EndPart1);
        string Part2 = StringToSplit.substr(EndPart1 + 1);
    }
    

    【讨论】:

    • 谢谢,如果这最终出现在某个开源程序中,我需要给你信用:)
    【解决方案5】:

    在 C++ 中没有内置的分割字符串的方法,但 boost 提供了 string algo 库来执行各种字符串操作,包括字符串 splitting

    【讨论】:

      【解决方案6】:

      这是我使用的 perl 风格的拆分函数:

      void split(const string& str, const string& delimiters , vector<string>& tokens)
      {
          // 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);
          }
      }
      

      【讨论】:

      • 我喜欢这个解决方案。与大多数其他解决方案不同,它不需要提升、组合分隔符、支持多个分隔符、有据可查,并且对于像我这样的菜鸟来说相当紧凑且易于理解。我只是将 demeters 参数更改为默认值,如原始:oopweb.com/CPP/Documents/CPPHOWTO/Volume/… :-)
      • 另外,像我这样的菜鸟应该小心地在每次调用这个函数时清除向量,如果他们希望它只保存最后一组标记! (使用 tokens.clear())。
      • 搜索中出现的旧线程。我会将split 的签名更改为没有第三个参数,而是返回vector&lt;string&gt;tokens 将是一个局部变量)。
      【解决方案7】:

      什么鬼……这是我的版本……

      注意:拆分 ("XZaaaXZ", "XZ") 将为您提供 3 个字符串。其中 2 个字符串将为空,如果 theIncludeEmptyStrings 为 false,则不会添加到 StringVector。

      分隔符不是集合中的任何元素,而是与该确切字符串匹配。

       inline void
      StringSplit( vector<string> * theStringVector,  /* Altered/returned value */
                   const  string  & theString,
                   const  string  & theDelimiter,
                   bool             theIncludeEmptyStrings = false )
      {
        UASSERT( theStringVector, !=, (vector<string> *) NULL );
        UASSERT( theDelimiter.size(), >, 0 );
      
        size_t  start = 0, end = 0, length = 0;
      
        while ( end != string::npos )
        {
          end = theString.find( theDelimiter, start );
      
            // If at end, use length=maxLength.  Else use length=end-start.
          length = (end == string::npos) ? string::npos : end - start;
      
          if (    theIncludeEmptyStrings
               || (   ( length > 0 ) /* At end, end == length == string::npos */
                   && ( start  < theString.size() ) ) )
            theStringVector -> push_back( theString.substr( start, length ) );
      
            // If at end, use start=maxSize.  Else use start=end+delimiter.
          start = (   ( end > (string::npos - theDelimiter.size()) )
                    ?  string::npos  :  end + theDelimiter.size()     );
        }
      }
      
      
      inline vector<string>
      StringSplit( const  string  & theString,
                   const  string  & theDelimiter,
                   bool             theIncludeEmptyStrings = false )
      {
        vector<string> v;
        StringSplit( & v, theString, theDelimiter, theIncludeEmptyStrings );
        return v;
      }
      

      【讨论】:

        【解决方案8】:

        一个相当简单的方法是使用 std::string 的 c_str() 方法获取 C 风格的字符数组,然后使用 strtok() 对字符串进行标记。不像这里列出的其他一些解决方案那样雄辩,但它很容易并且有效。

        【讨论】:

        • strtok 写入指向的内存。 c_str() 指向不能写入的内存(字符串类的不变量 - 可能会默默地破坏诸如写时复制语义之类的东西)。 C++ 标准禁止它。你可以先复制到 std::vector,然后你可以使用 strtok。
        • c_str 方法返回一个指向内部表示的 const 字符串。它是 const 因此您还必须将其 strdup 或将其复制到向量中。要求使用 C++ 方式,所以我对此表示反对。
        【解决方案9】:

        是的,字符串流。

        std::istringstream oss(std::string("This is a test string"));
        std::string word;
        while(oss >> word) {
            std::cout << "[" << word << "] ";
        }
        

        【讨论】:

        • 这是我的主力分离器。如果要在分隔符上拆分,只需将 oss&gt;&gt;word 替换为 getline(oss, word, ':')
        【解决方案10】:

        没有常见的方法。

        我更喜欢boost::tokenizer,它只有标题并且易于使用。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-11-29
          • 1970-01-01
          • 1970-01-01
          • 2021-08-11
          • 2011-02-22
          • 1970-01-01
          • 1970-01-01
          • 2015-05-26
          相关资源
          最近更新 更多