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

For every possible pair of two unique words in the file, print out the count of occurrences of that pair

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

#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 Cat, The Sat, The On, The The, The Mat, Cat The, Cat Sat, Cat On, 30 对)

确定文件中单词对频率的作业的目的是让您在 system 调用中包装 shell 实用程序的管道字符串,这似乎是不可想象的。这可能教会了你关于 C 的什么?是否存在允许 shell 访问的 system 函数?好吧,确实如此,你也可以,教训完了,什么都没学到。

似乎更有可能的目的是让您了解 结构 的用途,以在单个对象中保存相关数据的集合,或者至少 arraypointer indexing 检查文件中相邻单词的对。在 2 种常规方法中,使用结构或索引算法,使用结构要有利得多。一些简单的东西来保存一对单词,你只需要看到这对单词的频率。例如:

enum { MAXC = 32, MAXP = 100 };

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

(注意,enum 简单地定义了常量 MAXC (32) 和 MAXP (100) 用于每个单词的最大字符数,和要记录的最大对数。您可以在同一端使用两个 #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));
}

Use/Output

鉴于您的 "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

(不要求您对结果进行排序,但它使 lookup/confirmation 对于较长的文件更容易)

删除 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.

关系不大

仔细查看,在 手册页 中查找您不熟悉的功能,然后询问任何您不明白的问题。