问题:给定一个txt文件,找到文档中所有字母的标准化频率。
例如,如果给定的letters.txt包含“aaabb”
输出将是:
信|频率
0.6
b 0.4
应忽略非字母或数字。
到目前为止我的解决方案:
由于他们想要输入文本文件,我的main()应该接收命令行参数。
int main (int argc, char* argv[]){
我使用getchar()
进行了EOF检查 while ((c=getchar()) != EOF){
和if语句,用于检查getchar()的char是否在a-> z或A-> Z的ASCII值范围内
if (argv[1][c] >= 'a' && argv[1][c] <= 'z' || argv[1][c] >= 'A' && argv[1]<= 'Z')
这里有两件事 - 我不知道argv [1] [c]是否是写这篇文章的正确方法,但直觉上对我来说是有意义的。
一旦检查满足,我希望相应的字母更新一个专门针对其字母表中#位置的计数。因此,每次找到该字母时都需要一个为该字母迭代的声明数组。
count[26];
这是我在计数数组中将字母a或A与位置计数[0]相关联的麻烦。我不知道如何编写这部分代码。
答案 0 :(得分:1)
为什么不创建一个大小为52的int
数组,并且数组的前半部分用于小写字符计数而上半部分用于大写?
所以在伪代码中:
#define ALPHA_COUNTS (52)
#define UPPER_OFFSET (26)
int counts[ALPHA_COUNTS] = {0};
for (char c : the_file_stream) {
if (c is an alphabet character) {
if (c is a lowercase character){
++counts[c - 'a'];
} else {
++counts[c - 'A' + UPPER_OFFSET];
}
}
}
更简单的方法是只为所有ASCII字符创建一个表,并只填充字母字符:
#define ASCII_COUNT (127)
int counts[ASCII_COUNT] = {0};
for (char c : the_file_stream) {
if (c is an alphabet character) {
++counts[c];
}
}
然后,您可以遍历[Aa-Zz]的集合并检查每个字符的计数。
答案 1 :(得分:1)
通过计算所有输入的出现次数来简化统计数据收集 在结果中应忽略非字母或数字。
unsigned long long count[UCHAR_MAX + 1] = {0};
int ch;
while ((ch=getchar()) != EOF){
count[ch]++;
}
现在只对字母
求和unsigned long long sum = 0;
for (int i=0; i<=UCHAR_MAX; i++) {
if (isalpha(i)) {
sum += count[i];
// fold into lower case
if (isupper(i)) {
count[tolower(i)] += count[i];
count[i] = 0;
}
}
}
打印频率
for (int i=0; i<=UCHAR_MAX; i++) {
if (isalpha(i) && count[i] > 0) {
printf("%c %f\n", i, 1.0*count[i]/sum);
}
}
答案 2 :(得分:1)
有许多不同的方法可以解决这个问题。您可以使用ctype.h
中提供的功能(例如isalpha
,tolower
,toupper
等),或者对于所需的有限数量的测试,您可以简单地使用使用算术或基本按位运算直接测试字符。例如,您可以测试'a'
和'z'
之间的值是否为小写,对于所有字符,6th-bit
中的7-bit ASCII
是情况 - 位,所以简单地切换大小写位会将字符从上到下更改,反之亦然。
读然后分析方法 chux 概述了一个很好的方法。只要您可以将输入/输出与处理数据分开,就可以为自己提供很大的灵活性。
使用该逻辑,使用算术和简单按位运算来分析文件中出现的 alpha - 字符([A-Za-z]
)频率的示例可以类似于以下内容编写。 注意,程序将从作为第一个参数提供的文件名中读取(如果没有给出文件名,则默认来自stdin
:
#include <stdio.h>
#include <limits.h>
int main (int argc, char **argv) {
unsigned long long count[UCHAR_MAX + 1] = {0}, sum = 0;
int c, i;
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
while ((c = fgetc(fp)) != EOF) count[c]++; /* fill count */
for (i = 0; i <= UCHAR_MAX; i++) {/* freq of only chars */
if ('A' <= i && i <= 'Z') { /* fold upper-case */
count[i ^ (1u << 5)] += count [i]; /* into lower */
count[i] = 0; /* zero index */
}
if ('a' <= i && i <= 'z') /* if lower-case */
sum += count[i]; /* add to sum */
}
printf ("\n total characters [A-Za-z]: %llu\n\n", sum);
for (i = 0; i <= UCHAR_MAX; i++)
if (count[i] > 0 && ('a' <= i && i <= 'z'))
printf (" %c%c : %.2f\n", i ^ (1u << 5), i, 1.0 * count[i]/sum);
putchar ('\n');
if (fp != stdin) fclose (fp); /* close if not stdin */
return 0;
}
示例使用/输出
使用'aaabb'
程序的示例生成以下内容:
$ ./bin/char_freq < <(echo "aaabb")
total characters [A-Za-z]: 5
Aa : 0.60
Bb : 0.40
稍长的示例显示仅[A-Za-z]
的完整字符选择:
$ ./bin/char_freq < <(echo "*(a)123A_a/B+4b.")
total characters [A-Za-z]: 5
Aa : 0.60
Bb : 0.40
查看此答案以及所有其他答案,如果您有其他问题,请告诉我。