我们得到了一个包含一些文本的文本文件,我们需要打印出每个单词的出现率。如果同一个单词是大写的,那就不重要了。例如:“immenso”和“IMMENSO”被认为是同一个词
我有点做过,但不是真的,在这个意义上说,它打印出比我想要的更多。问题是我不知道为什么它不工作。
正文是:
Mi illumino di immenso
Illumino di immenso
Di immenso
IMMENSO
结果应该是
immenso 4
di 3
illumino 2
Mi 1
这是我到目前为止所做的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define N 100
typedef struct words {
int iteration;
char word[N];
} word_s;
int
main()
{
FILE *file;
file = fopen("file", "r");
word_s v[N];
if (file == NULL) {
printf("Error");
exit(1);
}
int i = 0,
j = 1,
n = 0;
char str[N];
while (fscanf(file, "%s", str) != EOF) {
if (n == 0) {
strcpy(v[n].word, str);
v[n].iteration = 1;
}
for (i = 0; i < n; i++) {
if (stricmp(v[i].word, str) != 0) {
strcpy(v[n].word, str);
v[n].iteration = 1;
}
if (stricmp(v[i].word, str) == 0) {
v[i].iteration++;
}
}
n++;
}
for (i = 0; i < n; i++) {
printf("word %s: %d iterations \n", v[i].word, v[i].iteration);
}
return 0;
}
基本上,我在while循环中尝试做的是,对于从fscanf(...,"%s",...);
中获得的每个新单词,我们将其与已存储的单词进行比较,如果它不存在于已存储的数据结构中,则添加它,否则如果我们发现它已经存储,则递增计数器。
本来我想把n++加到这部分
if(stricmp(v[i].word,str)!=0)
{
strcpy(v[n].word,str);
v[n].iteration=1;
n++
}
但是没有用
我得到的结果是:
Mi 1
illumino 2
di 3
immenso 4
Illumino 1
di 2
immenso 3
Di 1
immenso 2
IMMENSO 1
所以基本上它已经存储了每个单词,并从该位置开始计数。
你知道吗?
1条答案
按热度按时间wydwbb8l1#
好了,让我们来看看一种方法,你可以通过蛮力的方式来获得一个独特的单词集合,而不需要使用二叉树或哈希表,只需要使用一个很好的旧
for
循环来检查所有现有的单词。正如上面的注解中提到的,第一个单词不需要特殊情况。只需使用
for
循环并循环for (i=0; i<n; i++)
,当n
为零时,将完全跳过循环。在上面的代码中,你有另一个逻辑错误,关于
n
何时递增。因为你关心的是重复的单词,所以你只想在添加一个单词时递增n
(数组中的单词数),而不是在每次迭代时。还有一个可选的注意事项没有在您的问题中指定。由于您只关心不区分大小写的比较,您是否需要在转换为小写之前以原始大小写打印出单词?保存原始大小写的第二个数组是保存它的方便方法。您可以使用
struct
来保存str
和lowercase_str
(并使用这些数组),或者您可以简单地使用两个2D数组,其中公共索引协调每个单词。(struct
数组是更优雅的解决方案)(Note:一个
100 x 100
字符数组只有10 k的存储空间--在Windows上默认的1 M堆栈最小值是微不足道的,在Linux上默认的4 M堆栈更是微不足道。在Windows上你可能有大约100个这样的字符数组...)正如注解中提到的,
stricmp()
(例如strcasecmp()
)不是最快的函数,也不是标准C(它是POSIX)。您可以简单地使用循环来转换为小写使用tolower()
并确保可移植性。(尽管几乎所有编译器都支持POSIX函数-通过适当的定义)也就是说,您可以像下面这样更改代码,以获取文件中的唯一单词。你应该把文件名作为你程序的第一个参数(或者默认从
stdin
读取)。另一种方法是提示用户并读取文件名作为输入。你不需要重新编译你的代码只是为了从不同的输入文件读取。把所有的部分放在一起,你可以做一些类似于下面的事情(可选的第二个单词数组保留输出的原始大小写),例如。
两大注意事项:
(1)你没有任何需要
#include <stdlib.h>
的东西。只包括你需要的头文件。当你使用一个函数时--在手册页中查找它(例如在man7.org - Online Man Pages。每个函数的手册页(虽然一开始很神秘)提供了关于如何使用每个函数的简明信息--包括所需的头文件;(2)当阅读字符到数组中时,你不能单独使用
"%s"
。你必须使用 field-width 修饰符来防止写入超出数组边界。在你的情况下,最多100个字符,必须将fscanf()
的读取限制为99
字符与"%99s"
(以确保为nul-terminating字符'\0'
保留1个字符的存储空间(相当于普通的0
)。示例使用/输出
使用文件
dat/uniquewords.txt
中的数据,您可以执行以下操作:它输出保存在
words
数组中的原始大小写的唯一单词。小写单词数组lcwords
用于比较重复的单词。还要注意found
标志是如何用于只添加未找到的单词的(您也可以使用i == n
-由您决定)如果你有问题就告诉我。
使用Array of struct添加出现次数
根据您的注解,您需要捕获出现
count
,您可以通过简单地将else
添加到if (!found)
块来实现。本质上,您的逻辑是:重写以使用struct* 的 * 数组(可选地保存第一次出现的原始形式)和小写形式,您可以重新排列如下,同时添加出现
count
:示例使用/输出
使用相同的数据文件,输出现在将是:
告诉我这是否对你有用。