我是c ++的初学者(花了几个课,然后一段时间没有c ++,然后几个月后重新开始),我试着用一个简单的句子计算单词的数量,然后计算同一句话中的数字。为了计算单词,我使用:
int countWord(char *word)
{
int counter = 0;
char *words = strtok(word, " 0123456789-");
while (words != NULL)
{
counter++;
words = strtok(NULL, " 0123456789-");
}
return counter;
}
数字计数器基本相同,而不是使用整数我使用字母表。
char *num = strtok(number, " abcdefghijklmnopqrstuvwxyz");
我的主要是:
int main()
{
char str[] = "what time is 88 it 99today";
cout << "words = " << countWord(str) << " " << "numbers = " <<
countNum(str) << endl;
system("pause");
return 0;
}
当我运行它时输出:words = 3 numbers = 2.
当我将主要重新排列为:
char str[] = "what time is 88 it 99today";
cout << "words = " << countWord(str) << " ";
cout << "numbers = " << countNum(str) << endl;
输出为:words = 5 numbers = 0
任何人都可以解释为什么这是不正确的?此外,如果有人可以推荐我的文字,我会很感激。我从中学到的文字是:“C ++编程:D.S.Malik编写的包含数据结构的程序设计。我在本书中没有看到任何计算”单词“的技巧。谢谢。
答案 0 :(得分:2)
问题是strtok
用空字符标记原始字符串中的标记结束。引自cppreference:
如果找到这样的字符,它将被替换为空字符'\ 0',并且指向后面字符的指针存储在静态位置以供后续调用。
注意:此函数具有破坏性:它将'\ 0'字符写入字符串str的元素中。特别是,字符串文字不能用作strtok的第一个参数。
在你的情况下,行
cout << "words = " << countWord(str) << " " << "numbers = " <<
countNum(str) << endl;
是operator<<
的组合,如
...operator<<(operator<<(cout, "words"), countWord(str))...
首先评估第countNum(str)
行。然后,第二次评估countWord(str)
。这与
cout << "words = " << countWord(str) << " ";
cout << "numbers = " << countNum(str) << endl;
其他方式发生。
一种解决方案是在使用strtok
时使用原始字符串的副本,例如每次都使用strtok(strdup(str))
。更好的是,使用标准的C ++库特性,如std::string
,std::count_if
等。我确信有很多关于使用纯C ++的字数统计解决方案。
答案 1 :(得分:1)
Vlad为您的C风格代码提交了一个很好的答案。我的答案是展示使用更多的C ++库来帮助解决问题:
#include <iostream>
#include <string>
#include <vector>
#include <regex>
int main() {
// The main string.
std::string str = "what time is 88 it 99today";
// Space is your delimiter
std::string delimiter = " ";
// Create a regex string for matching numbers, including floating point.
std::regex number_chars(std::string("[0123456789.]+"));
// A lambda function to help tokenize strings.
// Returns a vector of substring tokens.
// The internal code is taken from an answer on Stack Overflow.
auto tokenizer = [](std::string s, std::string delimiter) {
size_t pos = 0;
std::string token;
std::vector<std::string> tokens;
while (pos = (s.find(delimiter))) {
token = s.substr(0, pos);
tokens.push_back(token);
s.erase(0, pos + delimiter.length());
if (pos == std::string::npos)
break;
}
return tokens;
};
// Apply the lambda.
auto tokens = tokenizer(str, delimiter);
// Output your tokens.
for (auto it : tokens) {
std::cout << it << "\n";
} std::cout << "\n";
// Output tokens that are numbers.
for (auto it : tokens) {
if (std::regex_match(it, number_chars)) {
std::cout << "String: " << it << " is a number.\n";
}
}
return 0;
}
由于C ++在C ++ 11中有一个正则表达式库,因此利用它会很好。