【问题标题】:Strtok and Char* [duplicate]Strtok 和 Char* [重复]
【发布时间】:2014-04-30 09:54:33
【问题描述】:

我有一个简单的代码,我试图通过char* 并将其吐出成单独的单词。这是我的简单代码。

#include <iostream>
#include <stdio.h>
int main ()
{
   char * string1 = "- This is a test string";
   char * character_pointer;
   std::cout << "Splitting stringinto tokens:" << string1 << std::endl;
   character_pointer = strtok (string1," ");
   while (character_pointer != NULL)
   {
       printf ("%s\n", character_pointer);
       character_pointer = strtok (NULL, " ");
   }
   return 0;
}

我收到一个不允许我执行此操作的错误。

所以我的问题是,我如何通过并找到char* 中的每个单词。对于我正在处理的实际程序,我的一个库将一段词作为const char* 返回,我需要使用词干算法来词干每个词(我知道如何做到这一点,我只是不知道如何发送词干分析器的每个单词)。如果有人可以解决如何让示例代码工作,我将能够弄清楚。所有在线示例都使用char[] 代替string1 而不是char*,我不能这样做。

【问题讨论】:

  • 不要使用strtok。它被彻底破坏了,在 C++ 中,使用标准库中的算法有更好的解决方案。
  • 这不是C++,主要是C
  • @DumbCoder 我从未使用过 C 并且正在尝试在 C++ 中使用它,所以如果我弄错了,我会道歉。詹姆斯有什么更好的方法来解决这个问题?
  • @JamesKanze,在 C++11 之前,如何使用 C++ 解决这个问题?我曾尝试替换 strtok 以进行标记化,但在没有性能受到影响的情况下始终无法这样做。我想 strtok 重新使用已经分配的字符串这一事实使它非常快。
  • 为什么要这样混合C和C++?在 C 中使用 printf,在 C++ 中使用 cout

标签: c++ strtok


【解决方案1】:

这是我知道的在 c++ 中拆分字符串的最简单(代码方面)方法:

std::string string1 = "- This is a test string";
std::string word;
std::istringstream iss(string1);
// by default this splits on any whitespace
while(iss >> word) {
    std::cout << word << '\n';
}

如果你想指定分隔符,也可以这样。

while(std::getline(iss, word, ' ')) {
    std::cout << word << '\n';
}

【讨论】:

    【解决方案2】:

    这是一个修正版,试试看:

    #include <iostream>
    #include <stdio.h>
    #include <cstring>
    int main ()
    {
       char string1[] = "- This is a test string";
       char * character_pointer;
       std::cout << "Splitting stringinto tokens:" << string1 << std::endl;
       character_pointer = strtok (string1," ");
       while (character_pointer != NULL)
       {
           printf ("%s\n", character_pointer);
           character_pointer = strtok (NULL, " ");
       }
       return 0;
    }
    

    【讨论】:

      【解决方案3】:

      在 C++ 中有多种方法可以做到这一点。

      如果空格是您的分隔符,那么您可以通过这种方式获取令牌:

      std::string text = "- This is a test string";
      std::istringstream ss(text);
      std::vector<std::string> tokens;
      std::copy(std::istream_iterator<std::string>(ss),
                std::istream_iterator<std::string>(),
                std::back_inserter<std::vector<std::string>>(tokens));
      

      您还可以使用正则表达式在 C++ 中标记字符串。

      std::string text = "- This is a test string";
      std::regex pattern("\\s+");
      std::sregex_token_iterator it(std::begin(text), std::end(text), pattern, -1);
      std::sregex_token_iterator end;
      for(; it != end; ++it)
      {
         std::cout << it->str() << std::endl;
      }
      

      【讨论】:

      • 请注意,&lt;regex&gt; 支持已添加到 gcc 的 version 4.9 中的 libstdc++。
      • 我没有看到任何 gcc 参考,但是是的,这是真的。
      • 你的假设也不成立。 OP 的代码在空格处中断,您的代码在任何非字母或连字符处中断。
      • 是的,谢谢你的指点。我已经更新了答案。新版本应该是正确的。
      • 对于像他这样简单的事情(事实上,strtok 可以做的大部分事情),正则表达式是矫枉过正的,使用istream 是非常超重的,而且不是很灵活。 std::find_first_ofstd::search 之类的东西要简单得多。
      【解决方案4】:

      忘记strtok。得到你的样子 目标:

      std::string const source = "- This is a test string";
      std::vector<std::string> tokens;
      std::string::const_iterator start = source.begin();
      std::string::const_iterator end   = source.end();
      std::string::const_iterator next  = std::find( start, end, ' ' );
      while ( next != end ) {
          tokens.push_back( std::string( start, next ) );
          start = next + 1;
          next = std::find( start, end, ' ' );
      }
      tokens.push_back( std::string( start, next ) );
      

      当然,这可以随意修改:你可以使用 std::find_first_of 是否需要多个分隔符,或者 std::search 如果你想要一个多字符分隔符,甚至 std::find_if 用于任意测试(使用 lambda,如果你有 C++11)。在大多数你解析的情况下,你可以 只需传递两个迭代器,而不必构造 一个子串;你只需要构造一个子字符串,当你 想要将提取的令牌保存在某处。

      一旦你习惯了使用迭代器和标准 算法,你会发现它比strtok灵活得多, 它没有内部的所有缺点 状态暗示。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-01
        • 2014-10-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多