C++分词标准字符串。

9

可能是重复问题:
如何在C++中对字符串进行标记化?

你好,我想知道如何使用strtok对std字符串进行标记化。

string line = "hello, world, bye";    
char * pch = strtok(line.c_str(),",");

我遇到了以下错误。
error: invalid conversion from ‘const char*’ to ‘char*’
error: initializing argument 1 of ‘char* strtok(char*, const char*)’

我正在寻找一种快速简便的方法,因为我认为这不需要太多时间。

我以前见过这种问题。可能是重复的。 - Hindol
4个回答

18

我通常使用getline来执行这样的任务。

istringstream is(line);
string part;
while (getline(is, part, ','))
  cout << part << endl;

11
std::string::size_type pos = line.find_first_of(',');
std::string token = line.substr(0, pos);

为了找到下一个标记,重复使用find_first_of函数,但从pos + 1位置开始。


有了这个,就必须再加一个变量来跟踪pos1和pos2。否则,你会使用从0到新位置的子字符串,而不是pos1到pos2。 - anthony

4
你可以使用 strtok,通过 &*line.begin() 获取一个非常量指向 char 缓冲区的指针。但我通常更喜欢在 C++ 中使用 boost::algorithm::split

我认为通过丢弃字符串内部指针上的const限定符,你允许strtok修改字符串的内部指针 - 这非常不好。 - Matt
1
这是一个糟糕的想法。它会使 std::string 进入未定义状态。你不应该使用 C 字符串函数修改 std::string - japreiss
1
@japreiss 怎么可能出错呢?通过迭代器修改字符串中的字符没有任何问题,而且C++字符串在实践中始终是连续的(http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#530),并且在C++11中保证是连续的和以null结尾。 - spencercw
@spencercw:不能保证字符串的内部表示是以零结尾的;而且它可能使用写时复制语义,在这种情况下,破坏“const”可能会更改字符串的其他副本。也许(也可能不)可以证明你正在做的事情对于任何符合规范的实现都是定义良好的,但即使你能够这样做,我也不想测试符合性的边缘情况。 - Mike Seymour
@MikeSeymour 在C++11中,内部缓冲区保证以空字符结尾(请参见此答案)。您提出了一个有趣的问题,即写时复制。我猜在这样的实现中,解引用迭代器会触发复制,或者当strtok写入缓冲区时,某种内存保护也会触发复制。是否有任何实际执行CoW的实现? - spencercw
@spencercw:不,C++11并不保证缓冲区是以零结尾的;只是字符串的字符被连续存储,s[s.size()] == 0s.data()s.c_str()返回指向以零结尾的数组的const指针。实际上,这意味着任何明智的实现都将使用以零结尾的连续缓冲区,但不能保证。GCC使用CoW;他们可能已经解决了通过指向解引用迭代器访问的所有棘手细节,但我个人不想依赖于此。 - Mike Seymour

1

strtok 是一个相当奇怪、邪恶的函数,它会修改其参数。这意味着你不能直接在 std::string 的内容上使用它,因为没有办法从该类中获取可变的、以零结尾的字符数组的指针。

你可以对字符串数据进行副本操作:

std::vector<char> buffer(line.c_str(), line.c_str()+line.size()+1);
char * pch = strtok(&buffer[0], ",");

或者更贴近 C++ 语言习惯的做法是使用字符串流:

std::stringstream ss(line);
std::string token;
std::readline(ss, token, ',');

或者更直接地找到逗号:

std::string token(line, 0, line.find(','));

没有std::readline()。你是不是想用std::getline()? - Artur Opalinski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接