2011-12-15 139 views
4

我有一個需要從中提取單詞的輸入文件。單詞只能包含字母和數字,因此其他任何內容都將被視爲分隔符。我試過fscanf,fgets + sscanf和strtok,但似乎沒有任何工作。在C中讀取文件

while(!feof(file)) 
{ 
    fscanf(file,"%s",string); 
    printf("%s\n",string); 
} 

上面一個顯然行不通,因爲這樣我替換此行不使用任何分隔符:

fscanf(file,"%[A-z]",string); 

它讀取的第一個字不錯,但文件指針不斷倒帶等等它一遍又一遍地讀出第一個單詞。

所以我用與fgets讀的第一行和使用的sscanf:

sscanf(line,"%[A-z]%n,word,len); 
line+=len; 

此一不工作,要麼因爲無論我嘗試,我不能將指針移動到合適的位置。我試過strtok的,但我無法找到如何設置delimitters

while(p != NULL) { 
printf("%s\n", p); 
p = strtok(NULL, " "); 

這一個顯然以空白字符作爲delimitter但我delimitters字面上100S。

我在這裏錯過了什麼,因爲從文件中提取單詞看起來似乎是一個簡單的概念,但沒有我嘗試真正起作用?

回答

1

我會用:

FILE *file; 
char string[200]; 

while(fscanf(file, "%*[^A-Za-z]"), fscanf(file, "%199[a-zA-Z]", string) > 0) { 
    /* do something with string... */ 
} 

這跳過非字母,然後讀取最多199個字母的字符串。唯一的奇怪之處在於,如果您有超過199個字母的任何「單詞」,它們將被分成多個單詞,但您需要限制以避免緩衝區溢出......

3

考慮構建最小lexer。當處於狀態單詞只要它看到字母和數字就會保留在它中。當遇到其他事情時,它將切換到分隔符。然後它可以在分隔符中完全相反。

下面是一個簡單的狀態機的例子,這可能會有所幫助。爲了簡潔起見,它僅適用於數字。 echo "2341,452(42 555" | ./main將在單獨的行中打印每個數字。這不是一個詞法分析器,但在狀態之間切換的想法非常相似。

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

int main() { 
    static const int WORD = 1, DELIM = 2, BUFLEN = 1024; 
    int state = WORD, ptr = 0; 
    char buffer[BUFLEN], *digits = "1234567890"; 
    while ((c = getchar()) != EOF) { 
    if (strchr(digits, c)) { 
     if (WORD == state) { 
     buffer[ptr++] = c; 
     } else { 
     buffer[0] = c; 
     ptr = 1; 
     } 
     state = WORD; 
    } else { 
     if (WORD == state) { 
     buffer[ptr] = '\0'; 
     printf("%s\n", buffer); 
     } 
     state = DELIM; 
    } 
    } 
    return 0; 
} 

如果狀態的數目增加,你可以考慮更換if語句檢查當前狀態switch塊。通過讀取整個輸入到臨時緩衝區塊並遍歷整個塊來替代getchar可以提高性能。

如果需要處理更復雜的輸入文件格式,可以使用詞法分析器生成器,如flex。他們可以爲你定義狀態轉換和詞法分析器的其他部分。

0

你的分隔符是什麼?第二個參數strtok應該是一個字符串包含您的分隔符,而首先應該是指向您的字符串第一次輪則NULL算賬:

char * p = strtok(line, ","); // assuming a , delimiter 
printf("%s\n", p); 

while(p) 
{ 
    p = strtok(NULL, ","); 
    printf("%S\n", p); 
} 
+0

定界符是除a-z和A-Z以外的所有東西。 – Ihateparsing 2011-12-15 21:52:49

2

幾點:

首先,不使用feof(file)爲您的循環條件; feof將不會返回true直到您嘗試讀取文件的末尾,因此您的循環將經常執行一次。

其次,你提到了這一點:

fscanf(file,"%[A-z]",string);

它讀取的第一個字不錯,但文件指針不斷倒帶這樣一遍又一遍地讀的第一個字。

這並非如此;如果流中的下一個字符與格式說明符不匹配,則scanf將返回而不讀取任何內容,並且string未修改。

下面是一個簡單的,如果不雅的方法:它從輸入文件一次讀取一個字符,檢查它是否是字母或數字,如果是,則將其添加到字符串中。

#include <stdio.h> 
#include <ctype.h> 

int get_next_word(FILE *file, char *word, size_t wordSize) 
{ 
    size_t i = 0; 
    int c; 

    /** 
    * Skip over any non-alphanumeric characters 
    */ 
    while ((c = fgetc(file)) != EOF && !isalnum(c)) 
    ; // empty loop 

    if (c != EOF) 
    word[i++] = c; 

    /** 
    * Read up to the next non-alphanumeric character and 
    * store it to word 
    */ 
    while ((c = fgetc(file)) != EOF && i < (wordSize - 1) && isalnum(c)) 
    { 
     word[i++] = c; 
    } 
    word[i] = 0; 
    return c != EOF; 
} 

int main(void) 
{ 
    char word[SIZE]; // where SIZE is large enough to handle expected inputs 
    FILE *file; 
    ... 
    while (get_next_word(file, word, sizeof word)) 
    // do something with word 
    ... 
}