计算字符串中的单词
Posted
技术标签:
【中文标题】计算字符串中的单词【英文标题】:Counting words in a string 【发布时间】:2014-07-19 13:44:53 【问题描述】:我正在自学 C++。我编写了这个程序来数。我知道这不是最好的方法,但这是我能想到的。
我使用空格来计算单词的数量。这就是问题所在。
countWords(""); // ok, 'x.empty()' identifies it as an empty string.
countWords(" "); // 'x.empty()' fails, function returns 1.
p.s 我希望这个程序不计算诸如“!”、“?”之类的符号。作为词。这是我的代码:
#include <iostream>
#include <string>
int countWords(std::string x);
int main()
std::cout << countWords("Hello world!");
int countWords(std::string x)
if(x.empty()) return 0; // if the string is empty
int Num = 1;
for(unsigned int i = 0; i < x.size(); i++)
// if there is a space in the start
if(x[0] == ' ') continue;
// second condition makes sure that i don't count 2 spaces as 2 words
else if(x[i] == ' ' && x[i - 1] != ' ') Num++;
return Num;
【问题讨论】:
首先,empty
检查是多余的。其次,看看你脑海中的" 123 456 789"
会发生什么。为简洁起见,只需调用std::unique
,然后再调用std::count
空格即可。对于一次通过,std::find
ing 下一个空格和std::find_if_not
ing 下一个非空格重复也可以。
您在开始循环之前将Num
设置为1,因此在第二个示例中,代码必须返回1
x.empty()
在第二种情况下也必须返回false,因为您的字符串不为空(包含一个空格)
@UnholySheepm,我知道。但是如果我将 Num 设置为零,那么我就无法得到想要的结果。
@Blastfurnace 否,请参阅第一个条件。当第一个为真时,第二个永远不会运行。顺便说一句,+1 为您提供帮助。
@user3834119 我假设你的意思是你得到的比预期少 1,在这种情况下你可以添加另一个测试语句:x[i]=='\0'
因为零终止是字符串的结尾
【参考方案1】:
您的功能可以简化为:
int countWords(std::string x)
int Num = 0;
char prev = ' ';
for(unsigned int i = 0; i < x.size(); i++)
if(x[i] != ' ' && prev == ' ') Num++;
prev = x[i];
return Num;
这是demo
编辑:跟进评论:
这是用' '
替换其他字符的简单方法,认为可能有一个构建方法:
void replace(std::string &s, char replacer, std::set<char> &replacies)
for (int i=0; i < s.size(); i++)
if (replacies.count(s[i])) s[i] = replacer;
demo
【讨论】:
+1 以获得良好的编码。我希望该程序适用于“?”,“!”之类的符号,这些符号不应算作单词。你能推荐一个方法吗? @user3834119,所以您基本上希望"?","!"..
被视为现在处理空格,也许您可以将这些字符替换为空格。
@Ajavall 是的。你是怎么做到的(用空格替换它们)?【参考方案2】:
您的答案的问题是您正在计算后面有“ ”符号的单词数。我相信您从 Num = 1 开始,因为您不会计算最后一个单词。但是,仅当您正在分析的字符串不以 ' ' 结尾时才会发生这种情况。否则,您将多计算 1 个字。解决此问题的最简单方法是添加
if(x.back() == ' ')
Num--;
在返回答案之前。
【讨论】:
x[x.size() - 1]
只是x.back()
。【参考方案3】:
您的解决方案不充分。应用时会失败:
前导空格 尾随空格 只有空格 其他形式的空格您需要重新考虑您的算法应该如何工作,因为您只需要一个更复杂的方法来涵盖所有用例。
或者您可以避免重新发明***并使用 标准库 已经提供的内容,例如:
int countWords(const std::string& s)
std::istringstream isss;
return std::distance(std::istream_iterator<std::string>iss,
std::istream_iterator<std::string>);
这里std::istringstream
和std::istream_iterator
用于对字符串进行分词,std::distance
用于获取提取的分词个数。
【讨论】:
【参考方案4】:我找到了最好的使用字符串流:
int Count(const std::string &string)
stringstream ss(string);
char cmd[256] = 0;
int Words = 0;
while(true)
ss >> cmd;
if(!ss)
break;
Words++;
return Words;
输入:“亲爱的朋友你好”输出:4
即使应用也不会失败:
前导空格 尾随空格 只有空格 其他形式的空格【讨论】:
“输出:4”,输入在哪里? @Quest 试试这个。 std::stringstream ss("你在说什么?");输出:6 @user3834119:输出不应该是 6 吗? :O @Silnik 我们在这里计算的是单词,而不是字符。那句话有5个字。即使你尝试这个,“你好,我亲爱的朋友。” (4 个字)输出:5 @user3834119:那你还没有定义一个词是什么。这里的每个人都会期望一个单词是一串没有空格的字符。然后根据你的定义是:“!!!”,“我”,“土豆!”一个字?您没有在问题中提供足够的信息。【参考方案5】:这在我的机器上既简单又快速。它遍历字符串,使用bool
来跟踪
无论它是否在一个单词内,以及空格字符作为单词分隔符。我使用isspace()
库函数进行了测试,但这个switch
语句稍快。
int countwords(const std::string &str)
int count = 0;
bool in_word = false;
for (char ch : str)
switch (ch)
case '\t': case '\n': case '\v': case '\f': case '\r': case ' ':
in_word = false;
break;
default:
if (!in_word)
in_word = true;
++count;
break;
return count;
这很容易针对不同的单词分隔符进行扩展或修改。这是一个将任何非字母字符视为分隔符的版本。将 !isalpha()
调用更改为 isspace()
将得到与上述代码相同的结果。
int countwords(const std::string &str)
int count = 0;
bool in_word = false;
for (char ch : str)
if (!isalpha(ch)) // non-alpha chars are word delimiters
in_word = false;
else if (!in_word)
in_word = true;
++count;
return count;
【讨论】:
【参考方案6】:int countwords(std::string x)
int i, count = 0;
for (i = 0; i < x.size(); i++)
if (x[i] == ' ')
count++; //just count empty spaces
count++; //count++ is same as count+1,so there will be count+1 words in string
if (x.size() == 0)
count = 0;
return count;
【讨论】:
这不是真的 - 根据您的解决方案 countWords("Hello_____world!") = 5,其中 _ 是 ' ' 但在 cmets 中连续写入 4 个空格会被删除。 是的,我提到只有 1 个空格作为分隔符,但是你可以毫无问题地将这 4 个空格转换为一个【参考方案7】:所以在阅读了一些有用的 cmets 之后,我自己尝试了。这是我的解决方案。我已经检查了我的程序是否有最坏的情况。如果你们中的任何人,可以找到任何该程序不起作用的情况,请告诉我,以便我可以工作和改进它。
为了清楚起见,我们不想要像“,”,“!”这样的符号。 , "?", "." , "\n" 算作单词。但显然,正如我们在语言中所考虑的那样,“我”应该算作单词。我通过用空格替换它们来确保这一切。如果我错过了什么,请告诉我。
#include <iostream>
#include <string>
void replace(std::string& str, char x, char y);
int countWords(std::string x);
int main()
std::cout<<countWords(" \n \t Hello, world ! ");
void replace(std::string& str, char x, char y)
for(unsigned int i=0;i<str.size();i++)
if(str[i]==x) str[i]=y;
int countWords(std::string x)
replace(x,',',' ');
replace(x,'.',' ');
replace(x,'!',' ');
replace(x,'?',' ');
replace(x,'(',' ');
replace(x,')',' ');
replace(x,'\n',' ');
replace(x,'\t',' ');
replace(x,'"',' ');
if(x.empty()) return 0;
int Num=1;
for(unsigned int i=1;i<x.size();i++)
if(x[i]==' ' && x[i-1]!=' ') Num++;
if(x.back() == ' ') Num--;
return Num;
【讨论】:
怎么样?在函数替换中,const 限定符没有理由。并且函数 countWords 太慢了 @Quest 感谢您的建议。当您使用“?”时它会起作用。如果您能提出一种快速运行的方法,我们将不胜感激。 您应该尝试 Blastfurnace 的答案并添加更多开关盒【参考方案8】:在代码中加入下面几行
int Num;
if(x[0] == ' ') Num = 0;
else Num = 1;
这将消除字符串开头的空白计数
#include <iostream>
#include <string>
int countWords(std::string x);
int main()
std::cout << countWords("Hello world!");
int countWords(std::string x)
if(x.empty()) return 0; // if the string is empty
int Num;
if(x[0] == ' ') Num = 0;
else Num = 1;
for(unsigned int i = 0; i < x.size(); i++)
// if there is a space in the start
if(x[0] == ' ') continue;
// second condition makes sure that i don't count 2 spaces as 2 words
else if(x[i] == ' ' && x[i - 1] != ' ') Num++;
return Num;
【讨论】:
这是错误的。在你的情况下 countWords("Hello ") = 2以上是关于计算字符串中的单词的主要内容,如果未能解决你的问题,请参考以下文章