2014-02-24 51 views
2

我試圖解析一個文本文件,並將每個不同的單詞添加到哈希表中,將單詞作爲關鍵字,並將它們的頻率作爲值添加。問題被證明是閱讀部分:該文件是一個非常大的「普通」文本文件,因爲它具有標點符號和特殊字符。我想把所有非字母字符作爲字邊界來處理。我有一些基本的東西有此打算:C - 讀取非字母字符作爲字邊界

char buffer[128]; 
while(fscanf(fp, "%127[A-Za-z]%*c", buffer) == 1) { 
    printf("%s\n", buffer); 
    memset(buffer, 0, 128); 
} 

然而,電抗器時,它實際會達到由空格前面有一個非字母字符(如「的,貓(棕色)」將被讀爲「貓是「)。我知道這個代碼的問題是什麼,但我不知道如何繞過它。如果只是整行閱讀並手動進行解析,我會更好嗎?我正在嘗試scanf,因爲我覺得這是一個非常好的候選人,你可以使用格式字符串來處理迷你正則表達式。

+5

''%127 [A-Za-z]%* [^ A-Za-z]「'作爲一個簡單的修復。 – BLUEPIXY

+0

謝謝!這做了我所需要的。 –

+1

使用'while(fscanf(fp,「%* [^ A-Za-z]」),fscanf(fp,「%127 [A-Za-z]」,buffer)== 1 {'很好地處理''%127 [A-Za-z]%* [^ A-Za-z]「'不是。這兩種方法都可以很好地處理最後一個字母組,其次是非字母 – chux

回答

4

建議使用isalpha(),fgetc()和一個簡單的狀態機。

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

int AdamRead(FILE *inf, char *dest, size_t n) { 
    int ch; 
    do { 
    ch = fgetc(inf); 
    if (ch == EOF) return EOF; 
    } while (!isalpha(ch)); 

    assert(n > 1); 
    n--; // save room for \0 
    while (n-- > 0) { 
    *dest++ = ch; 
    ch = fgetc(inf); 
    if (!isalpha(ch)) break; 
    } 

    ungetc(ch, inf); // Add this is something else may need to parse `inf`. 
    *dest = '\0'; 
    return 1; 
} 

char buffer[128]; 
while(AdamRead(fp, buffer, sizeof buffer) == 1) { 
    printf("%s\n", buffer); 
} 

注意:如果你想要去的"%127[A-Za-z]%*[^A-Za-z]"航線,代碼可能需要先從一次性fscanf(fp, "*[^A-Za-z]");應對領先的非字母。

+0

爲什麼我們需要'ungetc(ch,inf);'? 'ch'是一個非字母字符,在下一次「AdamRead」調用時將被丟棄。 – ajay

+0

@ajay'ungetc(ch,inf)'在這裏應該是有用的,因爲在'AdamRead()'之後調用_different_函數可能會開始掃描非字母。 – chux

+1

@ajay也'ch' _may_是一封信。由於'n'變爲0,while循環可能已經停止.OP的函數定義是開放的,涉及在緩衝區填滿時要做什麼。通過放回這封可能的字母,它有機會在下一個函數調用中讀取。 – chux

0

除了評論中提到的方法之外,還有另外一種方法。我不知道這是否更好。您可以使用fgets從文件中讀取行,然後使用strtok_r POSIX函數對行進行標記。在這裏,r表示該函數是可重入的,這使得它是線程安全的。但是,您必須知道文件中行可以具有的最大長度。

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

#define MAX_LEN 100 

// in main 

char line[MAX_LEN]; 
char *token; 
const char *delim = "[email protected]#$%^&*"; // all special characters 
char *saveptr;  // for strtok_r 
FILE *fp = fopen("myfile.txt", "r"); 

while(fgets(line, MAX_LEN, fp) != NULL) { 
    for(; ; line = NULL) { 
     token = strtok_r(line, delim, &saveptr); 
     if(token == NULL) 
      break; 
     else { 
      // token is a string. 
      // process it 
     } 
    }  
} 

fclose(fp); 

strtok_r修改它的第一個參數line,所以你應該保持它的一個副本,如果它用於其他目的。