2011-12-15 11 views
4

私は単語を抽出する必要がある入力ファイルがあります。単語には文字と数字しか含めることができないため、他のものは区切り文字として扱われます。私はfscanf、fgets + sscanf、strtokを試しましたが、何も動かないようです。Cでファイルを読む

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

それは罰金最初の単語を読み取りますが、ファイルポインタがとても巻き戻し続け:私はこの行を置き換えて、それは任意の区切り文字を使用しないため1以上

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

は明らかに動作しません。最初の単語を何度も何度も読みます。

だから私は、最初の行を読み込み、sscanf関数を使用するためのfgetsを使用:この1つは動作しません

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

どちらか私は右の場所にポインタを移動することはできませんしてみてください何でもので。私はstrtokはを試みたが、私は明らかにdelimitters

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

この1セットdelimitterとして、空白文字を取るが、私はdelimittersの文字通り数百を持ってする方法を見つけることができません。

ファイルから単語を抽出すると、最初は単純なコンセプトだったようですが、実際には何も試みませんか?

答えて

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; 
} 

状態の数は、あなたがswitchブロックと現在の状態を確認if文を置き換えることを検討することができ増大した場合。 getcharを入力の全体ブロックを一時バッファーに読み込んでそれを反復処理することで、パフォーマンスを向上させることができます。

より複雑な入力ファイルフォーマットに対処する必要がある場合は、flexのような字句解析エンジンジェネレータを使用できます。彼らはあなたのために、状態遷移とレクサー生成の他の部分を定義する仕事をすることができます。

0

デリミタは何ですか?その後、その後NULLstrtokの二番目の引数は、あなたの区切り文字を含む文字列であるべきであり、最初のラウンドは初めてあなたの文字列へのポインタでなければなりません:

私が使用する
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

2

いくつかのポイント:すべての

まず、あなたのループ条件としてfeof(file)を使用しないでください。 feofは、の後にまでtrueを返しません。そのため、ループはあまりにも頻繁に実行されます。

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

それは罰金最初の単語を読み取りますが、ファイルポインタは、それが何度も最初の単語を読み込み、巻き戻し続ける:

第二に、あなたはこれを言及しました。

これはまったく起こりません。ストリームの次の文字が書式指定子と一致しない場合、scanfは何も読み取らずに返します。stringは変更されません。

入力ファイルから一度に1文字ずつ読み込み、アルファベットか数字かを確認し、そうであれば文字列に追加します。

#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 
    ... 
}