在C++中查找(奇怪的)字符串中的单词
Finding words in a (weird) string in C++
这个程序在技术上有什么错误?预期的结果是6,因为这是字符串中出现的单词总数。
#include <iostream>
using namespace std;
int main()
{
string str = " Let's count the number of words ";
int word = 0;
for (int i = 0; str[i] != ' ';)
{
if ((str[i] == 32 && str[i + 1] == 32) || (str[i] == 32 && str[i - 1] == 32))
{
++i;
}
else if ((str[i] == 32 && str[i - 1] != 32) || (str[i] == 32 && str[i + 1] != 32))
{
word++;
}
++i;
}
cout << "No. of words: " << word << endl;
return 0;
}
我的错误结果:
No. of words: 0
此外,如果我尝试将字符串中的空格,甚至字符串本身更改为一组全新的间隔单词,比如:
string str = " Hello world ";
string str = "Hello world! How are you? ";
我仍然得到不正确的结果,但与0不同。我是C++编程的新手,这些奇怪的行为让我做噩梦。这很常见吗?我能做些什么来纠正这个问题?
如果你能按照我写的方式突出显示或更正我的程序,这将对我很有帮助,也会让我很快理解错误,而不必在这一点上知道一些新命令。因为,正如我所说,我完全是C/C++的初学者。
谢谢你抽出时间!
我是C++编程的新手,这些奇怪的行为让我做噩梦。这很常见吗?
是的,这很常见。您已经编写了大量堆积在堆中的逻辑,但您没有工具来理解它的行为。
我能做些什么来纠正这个问题?
您可以从两个方向进行操作:
-
调试它以提高您对其操作方式的理解:
- 在每一行预先确定您希望它对一些短输入做什么
- 在调试器中执行一步,看看它实际做了什么
- 想想为什么它没有达到你的预期
有时问题是你的代码没有正确实现你的算法,有时算法本身也被破坏了,通常两者兼而有之。两者兼而有之会让你有所领悟。
-
首先编写更容易理解的代码(同样,编写易于推理的算法)。
这取决于你对是否容易推理有一些直觉,这是你从迭代步骤1中开发出来的。
。。。而不必在此时知道一些新命令。
好吧,无论如何,你都需要学会使用调试器,所以现在是开始的好时机。
我们当然可以改进现有的代码,尽管我更愿意修复逻辑。一般来说,我鼓励您将现有的if
条件抽象为一些小函数,但问题是它们目前似乎没有任何意义。
那么,我们如何定义一个词呢?
你的代码说它至少是一个非空格字符,前面是或后面是一个空格。(顺便说一句,你肯定更喜欢' '
而不是32
,std::isspace
比任何一个都好。)
然而,您的代码的隐含定义是有问题的,因为:
- 每一个超过一个字符的单词都有第一个和最后一个字符,您将计算每个字符
- 在不越界的情况下,无法检查第一个字符前面是否有任何内容
- 最后一个字符后面跟着null终止符,但不能将其视为空白
让我们选择一个不同的定义,它不需要读取str[i-1]
,也不需要当前代码出错的复杂遍历。
我声称一个单词是非空白字符的连续子串,单词由空白字符的相邻子串分隔。因此,我们可以编写伪代码来工作,而不是查看每对连续的字符:
for (current = str.begin(); current != str.end(); ) {
// skip any leading whitespace
current = find_next_non_whitespace(str, current);
if (current != str.end()) {
// we found a word
++words;
current = find_next_whitespace(str, current);
}
}
注:。当我谈到将代码抽象成小函数时,我指的是像find_next_non_whitespace
这样的东西——它们应该实现起来很简单,易于测试,并且有一个告诉你一些东西的名称。
当我说你现有的条件似乎没有意义时,这是因为更换
if ((str[i] == 32 && str[i + 1] == 32) || (str[i] == 32 && str[i - 1] == 32))
比如说
if (two_consecutive_spaces(str, i))
提示的问题多于回答的问题。为什么恰好有两个连续空间的特殊情况?只是一个空间不同吗?如果我们有两个单词之间只有一个空格,实际会发生什么?为什么在这种情况下我们前进两个字符,而在单词分支上只有一个字符?
代码不能很容易地映射回可解释的逻辑,这是一个坏迹象——即使它有效(我们知道它不起作用),我们也不太了解它,无法对其进行更改、扩展或重构
我认为您有一些方法可以做到这一点。与您的非常相似:
string s = " Let's count the number of words ";
int word = 0;
for (auto i = 0; s[i] != ' '; i++) {
if (i == 0) {
if (s[i] != ' ') {
++word;
}
continue;
}
if (s[i - 1] == ' ' && s[i] != ' ') {
++word;
}
}
cout << "No of Words: " << word << endl;
其思想是对逐字符读取的字符串进行迭代。所以我们做了一些逻辑:
- 如果我们在第一个字符串中,并且它等于",则转到下一个循环迭代
- 如果我们在第一个字符串中,并且它与"不同,则意味着我们正在开始一个单词,因此计算它并跳到下一个循环迭代
- 如果我们到达第二个
if
,则意味着我们不在第一个位置,因此尝试访问i - 1
应该是有效的。然后我们只检查前一个字符是否是空白,而当前字符是否不是。这意味着我们要开始一个新词。所以计算它并跳到下一个循环迭代
另一种更简单的方法是使用字符串流:
string s = " Let's count the number of words ";
stringstream ss(s);
string sub;
int word = 0;
while (ss >> sub) {
++word;
}
cout << "No of Words: " << word << endl;
通过这种方式,你基本上是从字符串中逐字逐句地提取。
- 从字符串变量中逐字符读取单词
- 使用std::mt19937从字符串中返回一个随机单词
- C++-字符串是否包含一个带有简单循环的单词
- 在C++中查找(奇怪的)字符串中的单词
- 当字符串是某个单词时给出输出?
- 替换字符串中的单词,但忽略引号中的单词
- 替换字符串位置 X 中的单词C++
- 视觉C++使用 map 来比较字符串中的每个单词
- 给定一个单词数组和一个字符串,如何计算给定字符串中的所有单词
- 输出返回编号。等于输入字符串的单词的字符串数
- 在字符串的每个单词的末尾插入字符串
- 分析字符串中的双精度和单词
- 如何使用运算符>>在自定义字符串中输入多个单词?
- 反转字符串中单词的位置,而不更改 O(1) 空格限制中特殊字符的顺序
- 使用正则表达式c++从单词和分隔符之间的字符串中提取所有子字符串
- 从文件 (C++) 输入两个单词字符串
- 在一行中输入具有其他输入类型的多个单词字符串
- 打印以 "a" 开头的单词(字符串中)
- 如何让我的代码以不会切断单词(字符串)的方式运行?
- 句子变成单词c++字符串