2016-04-03 62 views
-5

此代碼適用於單個字計數,並區分具有大寫小寫字母的標點符號字。有沒有簡單的方法來使這個代碼適用於配對,而不是單個單詞?就像我需要在文本文件中打印每對單詞的出現一樣。 你的幫助是非常讚賞,對於文件中每個可能的一對兩個唯一字,打印出該對的出現次數

#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 

輸出 (貓,星期六,該上時,所述的,墊,貓,貓星期六,貓開,對於30對)

+1

唉! 「在C」?你爲什麼不直接輸入該命令? –

+0

@weather葉片編輯 – user3328381

+1

這是一個任務嗎?你確定你可以使用'system'來調用外部工具嗎?分配通常要求您在不調用其他程序的情況下實現實際功能。 – kaylum

回答

0

您的任務確定文件中字對的頻率的目的似乎是不可思議的,那就是讓您在調用system時將shell實用程序的管道字符串包裝起來。那可能教你關於C的是什麼?存在允許shell訪問的system函數?那麼,它確實如此,而且你可以完成課程,沒有任何學問。

似乎更有可能的是,意圖是讓你瞭解使用結構的持有相關數據集合在一個單一的對象,或在最小陣列指針索引檢查對在文件中的相鄰詞語中。在2種常規方法中,使用結構或索引算術,使用結構更有利。簡單地容納一對單詞以及看到的對的頻率就是你所需要的。例如:

enum { MAXC = 32, MAXP = 100 }; 

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

(注意,該enum簡單定義的常量MAXC32)和MAXP100)每字最多字符,最大對記錄您可以用兩個#define語句同一端。 )

可以聲明的wordpair結構,這將保持在一對或單詞w1w2和多少時間對被認爲是在freq的陣列。結構數組可以像對待任何其他數組一樣對待,排序等。

要分析文件,只需將前兩個單詞讀入第一個結構,保存一個指向第二個單詞的指針,然後讀取文件中剩餘的剩餘單詞,比較由指針和新單詞形成的對是否已經存在(如果只是簡單地更新所看到的次數),並且如果它不存在,則添加一個新對以更新指向讀取的新單詞的指針,然後重複。

下面是一個簡短示例,它將檢查命令行中作爲參數給出的所有文件名中單詞的出現次數(例如./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 

(還有就是你對結果進行排序沒有要求,但它使查找/確認輕鬆了許多具有較長的文件)

刪除快速排序

$ 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沒什麼關係。

仔細查看,在手冊頁中查找對您而言是新手的函數,然後詢問您之後不瞭解的任何內容。

+0

非常感謝大衛!我只是想編譯程序gcc program.c然後./a.out words_file.txt但它不工作,有什麼建議嗎? – user3328381

+0

當然'gcc -Wall -Wextra filename.c'這會產生'a.out'。然後只需'./a.out filename'來讀取'filename'中的對。你也可以在你的編譯時加上'-o'併爲你的可執行文件指定一個真實的名字,例如'gcc -Wall -Wextra -o myexename filename.c',這將創建'myexename'作爲你的可執行文件。 –

+0

我使用了:'gcc -Wall -Wextra -Ofast -o bin/file_word_pairs file_word_pairs.c',它只是加了'-Ofast'優化。 –

相關問題