规范化给定.txt文件中字母的频率

时间:2016-04-01 20:48:54

标签: c command-line-arguments normalization word-frequency

问题:给定一个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]相关联的麻烦。我不知道如何编写这部分代码。

3 个答案:

答案 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中提供的功能(例如isalphatolowertoupper等),或者对于所需的有限数量的测试,您可以简单地使用使用算术或基本按位运算直接测试字符。例如,您可以测试'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

查看此答案以及所有其他答案,如果您有其他问题,请告诉我。