对于文件中每个可能的两个唯一单词对,打印出该对的出现次数

时间:2016-04-03 23:05:56

标签: c unix word-count

此代码适用于单个字数,它区分带有标点符号的单词和大写字母。是否有一种简单的方法可以使这个代码对于对,而不是单个单词?就像我需要打印文本文件中每对单词的出现一样。 非常感谢您的帮助,

#include <stdio.h>
#include <stdlib.h>


int main(int argc, char **argv)
 {
FILE* f = fopen (argv[1], "r");
char buffer[10000];
if (argc != 2)
{
    fprintf(stderr, "Usage: %s file\n", argv[0]);

}
fclose(f);
snprintf(buffer, sizeof(buffer), "tr -cs '[:punct:][a-z][A-Z]'   '[\\n*]' < %s |"
                                 " sort | uniq -c | sort -n", argv[1]);

return(system(buffer));
}

示例输入

 The Cat Sat On The Mat

输出      (猫,星期六,开启,The,The Mat,Cat The,Cat Sat,Cat On,30对)

1 个答案:

答案 0 :(得分:0)

似乎不可思议的是,您的作业确定文件中单词对的频率的目的是让您在system调用中包装管道字符串实用程序。那可能教你什么关于C?存在允许shell访问的system函数?嗯,确实如此,你可以,完成课程,没有学到任何东西。

似乎更有可能的目的是让您理解使用结构来保存相关数据的集合在一个对象中,或者至少数组指针索引以检查文件中相邻单词中的对。在2种常规方法中,使用结构或索引算法,结构的使用更有益。只需要容纳一对单词和看到对的频率就可以了。 e.g:

enum { MAXC = 32, MAXP = 100 };

typedef struct {
    char w1[MAXC];
    char w2[MAXC];
    size_t freq;
} wordpair;

(请注意,enum只是为每个单词的最大字符定义常量MAXC32)和MAXP100),最大值要记录的对。你可以在同一端使用两个#define语句

您可以声明wordpair结构的数组,该数组将包含一对或多个单词w1w2以及在freq中看到该对的时间。 struct数组可以像任何其他数组一样对待,排序等。

要分析文件,您只需要将前两个单词读入第一个结构,保存指向第二个单词的指针,然后读取保留在文件中的每个剩余单词,比较是否由指针和新单词read已经存在(如果是这样只是更新所看到的次数),如果它不存在,添加一个新对,更新指针指向新单词read,并重复。

下面是一个简短的示例,它将检查命令行中作为参数给出的所有文件名中单词的出现次数(例如./progname file1 file2 ...)。如果没有给出文件,默认情况下代码将从stdin读取。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

enum { MAXC = 32, MAXP = 100 };

typedef struct {
    char w1[MAXC];
    char w2[MAXC];
    size_t freq;
} wordpair;

size_t get_pair_freq (wordpair *words, FILE *fp);
int compare (const void *a, const void *b);

int main (int argc, char **argv) {

    /* initialize variables & open file or stdin for seening */
    wordpair words[MAXP] = {{"", "", 0}};
    size_t i, idx = 0;
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    /* read from file given, or from stdin (default) */
    idx = get_pair_freq (words, stdin);

    /* read each remaining file given on command line */
    for (i = 2; i < (size_t)argc; i++)
    {   if (fp && fp != stdin) { fclose (fp); fp = NULL; }
        /* open file for reading */
        if (!(fp = fopen (argv[i], "r"))) {
            fprintf (stderr, "error: file open failed '%s'.\n",
                        argv[i]);
            continue;
        }

        /* check 'idx' against MAXP */
        if ((idx += get_pair_freq (words, fp)) == MAXP)
            break;
    }
    if (fp && fp != stdin) fclose (fp);

    /* sort words alphabetically */
    qsort (words, idx, sizeof *words, compare);

    /* output the frequency of word pairs */
    printf ("\nthe occurrence of words pairs are:\n\n");
    for (i = 0; i < idx; i++) {
        char pair[MAXC * 2] = "";
        sprintf (pair, "%s:%s", words[i].w1, words[i].w2);
        printf ("  %-32s : %zu\n", pair, words[i].freq);
    }

    return 0;
}

size_t get_pair_freq (wordpair *pairs, FILE *fp)
{
    char w1[MAXC] = "", w2[MAXC] = "";
    char *fmt1 = " %32[^ ,.\t\n]%*c";
    char *fmt2 = " %32[^ ,.\t\n]%*[^A-Za-z0-9]%32[^ ,.\t\n]%*c";
    char *w1p;
    int nw = 0;
    size_t i, idx = 0;

    /* read 1st 2 words into pair, update index 'idx' */
    if (idx == 0) {
        if ((nw = fscanf (fp, fmt2, w1, w2)) == 2) {
            strcpy (pairs[idx].w1, w1);
            strcpy (pairs[idx].w2, w2);
            pairs[idx].freq++;
            w1p = pairs[idx].w2;    /* save pointer to w2 for next w1 */
            idx++;
        }
        else {
            if (!nw) fprintf (stderr, "error: file read error.\n");
            return idx;
        }
    }

    /* read each word in file into w2 */
    while (fscanf (fp, fmt1, w2) == 1) {
        /* check against all pairs in struct */
        for (i = 0; i < idx; i++) {
            /* check if pair already exists  */
            if (strcmp (pairs[i].w1, w1p) == 0 && 
                strcmp (pairs[i].w2, w2) == 0) {
                pairs[i].freq++;    /* update frequency for pair  */
                goto skipdup;       /* skip adding duplicate pair */
            }
        } /* add new pair, update pairs[*idx].freq */
        strcpy (pairs[idx].w1, w1p);
        strcpy (pairs[idx].w2, w2);
        pairs[idx].freq++;
        w1p = pairs[idx].w2;
        idx++;

    skipdup:

        if (idx == MAXP) { /* check 'idx' against MAXP */
            fprintf (stderr, "warning: MAXP words exceeded.\n");
            break;
        }
    }

    return idx;
}

/* qsort compare funciton */
int compare (const void *a, const void *b)
{
    return (strcmp (((wordpair *)a)->w1, ((wordpair *)b)->w1));
}

使用/输出

根据"Hi how are you are you."的示例,它会产生所需的结果(按照LOCALE的排序顺序)。

$ echo "Hi how are you are you." | ./bin/file_word_pairs

the occurrence of words pairs are:

  Hi:how                           : 1
  are:you                          : 2
  how:are                          : 1
  you:are                          : 1

(不要求您对结果进行排序,但是使用更长的文件可以更轻松地查找/确认)

删除qsort

$ echo "Hi how are you are you." | ./bin/file_word_pairs

the occurrence of words pairs are:

  Hi:how                           : 1
  how:are                          : 1
  are:you                          : 2
  you:are                          : 1

虽然您可以自由尝试使用system版本,但为什么不花时间学习如何在C中解决问题。如果您想通过system了解如何解决问题打电话,采取Linux课程,因为以这种方式这样做与C没什么关系。

仔细查看,在手册页中查找新手的功能,然后询问您之后无法理解的任何内容。