问题:统计字符串\(str\)中单词\(word\)出现的次数。已知字符串中的单词用一个空格或者多个空格隔开。
输入格式:有2行,第1行是字符串\(str\),第2行是不带空格的单词\(word\)。
分析:使用string来存储字符串\(str\)和单词\(word\)。可以通过string的find方法查找子串的方式统计单词出现次数,例如字符串和单词内容如下:
nice to meet you and how are you thank you very much you
初步想法是用find方法统计单词you
在字符串nice to meet you and how are you thank you very much
出现次数:
#include<iostream> #include<string> using namespace std; int main() { int cnt = 0; string str,word; getline(cin,str); cin>>word; //查找单词word第一次出现的位置 size_t pos = str.find(word); while(pos != string::npos){ //查找到 cnt++; //从pos+word.length()起继续查找单词word第一次出现的位置 pos = str.find(word,pos+word.length()); } cout<<cnt<<endl; return 0; }
但是考虑下面的情况:
nice to meet you and how are you thank you and your friends very much you
因为your
中也完整出现了单词you
,也会被统计到。find方法是查找子串,如果字符串\(str\)中某个单词中完整出现了单词\(word\)(此外还有其他字符),用上面的方法也会认为单词\(word\)出现了一次导致统计结果出错!那么该如何解决问题呢?
其实我们可以用find方法统计字符串" "+str+" "
中单词" "+word+" "
出现的次数,这样处理就能有效避免上面的问题(注意体会并掌握这种处理方法):
#include<iostream> #include<string> using namespace std; int main() { int cnt = 0; string str,word; getline(cin,str); str = " "+str+" "; cin>>word; word = " "+word+" "; //查找单词word第一次出现的位置 size_t pos = str.find(word); while(pos != string::npos){ cnt++; //从pos+word.length()起继续查找单词word第一次出现的位置 pos = str.find(word,pos+word.length()); } cout<<cnt<<endl; return 0; }
如果我们用字符数组存储字符串,那么该如何统计单词出现次数呢?其实我们使用前一小节例题中的方法将字符串中的每个单词找出来:
#include<iostream> #include<cstring> using namespace std; char str[1010]; int main() { char last = ' '; //记录上一个字符,体会这里默认值设置成空格字符的用途 fgets(str,sizeof(str),stdin); int n = strlen(str); //n是字符串长度 int start = 0; //start记录单词首字符下标 //处理fgets输入字符串末尾可能额外附带的'\n' if(n && str[n-1]=='\n') str[--n] = '\0'; for(int i=0;i<=n;i++){ //注意这里的条件是i<=n,而不是一般遍历字符串的i<n //如果上一个字符是空格、当前字符不是空格,则找到一个新单词 if(last == ' ' && str[i] != ' '){ start = i; //记录找到的单词的首字符下标 }else if(last != ' ' && (str[i] == ' ' || str[i] == '\0')){ //单词结束 //从start到i-1是一个单词 for(int j=start;j<i;j++) cout<<str[j]; cout<<endl; } //last更新为当前字符,在下一次循环中就成了“上一个字符” last = str[i]; } return 0; }
那么只需要判断每次找出来的单词是不是\(word\)就能统计单词\(word\)的数量了:
#include<iostream> #include<cstring> using namespace std; char str[1010],word[1010]; int main() { int cnt = 0; char last = ' '; //记录上一个字符,体会这里默认值设置成空格字符的用途 fgets(str,sizeof(str),stdin); cin>>word; int n = strlen(str); //n是字符串长度 int start = 0; //start记录单词首字符下标 //处理fgets输入字符串末尾可能额外附带的'\n' if(n && str[n-1]=='\n') str[--n] = '\0'; for(int i=0;i<=n;i++){ //注意这里的条件是i<=n,而不是一般遍历字符串的i<n //如果上一个字符是空格、当前字符不是空格,则找到一个新单词 if(last == ' ' && str[i] != ' '){ start = i; }else if(last != ' ' && (str[i] == ' ' || str[i] == '\0')){ //单词结束 int j,k; //从start到i-1是一个单词 //比较字符串str的start到i-1的字符与word的字符是否依次相等 for(j=start,k=0;j<i && word[k];j++,k++){ if(str[j] != word[k]) break; } //全部匹配相等,并且单词都匹配结束,那么匹配到单词word if(j==i && word[k]=='\0') cnt++; } //last更新为当前字符,在下一次循环中就成了“上一个字符” last = str[i]; } cout<<cnt<<endl; return 0; }