3


0

C:fscanf-最初の文字が一致した場合の無限ループ

fscanfを使用してテキスト(CSS)ファイルを解析し、このパターンに一致するすべてのステートメントを引き出しようとしています。

@import "some / file / somewhere.css";

これを行うには、次のループを設定します。

FILE *file = fopen(pathToSomeFile, "r");
char *buffer = (char *)malloc(sizeof(char) * 9000);

while(!feof(file))
{
    // %*[^@] : Read and discard all characters up to a '@'
    // %8999[^;] : Read up to 8999 characters starting at '@' to a ';'.
    if(fscanf(file, "%*[^@] %8999[^;]", buffer) == 1)
    {
        // Do stuff with the matching characters here.
        // This code is long and not relevant to the question.
    }
}

ファイルの最初の文字が「@」ではないので、これは完全に機能します。 (文字通り、CSSファイルの最初の「@」文字の前にスペースが1つあれば、コードは正常に実行されます。)

ただし、CSSファイルの最初の文字が「@」の場合、デバッガーに表示されるのは無限ループです。実行はwhileループに入り、fscanfステートメントにヒットしますが、「if」ステートメントは入力しません( fscanfが失敗します)、ループを永久に継続します。

私のfscanfフォーマッタには多少の調整が必要かもしれませんが、どのように進めたらよいかわかりません。 なぜこれが起こっているのかについての提案や説明はありますか?

ありがとうございました。

3 Answer


2


私は `scanf`パターン構文の専門家ではありませんが、あなたの解釈は次のとおりです。

  • 空ではない「 '@'」文字のシーケンスに一致してから、

  • 最大8999個の非 ’;'`文字の空でないシーケンスに一致します

そのため、文字列が「 '@'」で始まる場合、最初の部分は失敗します。

書式文字列を空白文字で開始すると、データストリング内の先頭の空白文字をすべて fscanf`が消費します。 単に `"%8999 [^;] "


1


オリはすでにfscanfが失敗した理由を述べました。 また、失敗はfscanfの通常の状態であるため、ビジーループはfscanfの失敗の結果ではなく、処理の欠落によるものです。

入力が常にフォーマットに一致することを確認できないため、フォーマットが正しい場合(特別な場合)でもfscanfの失敗を処理する必要があります。 実際、一致する入力よりもはるかに多くの不一致の入力が存在することを確認できます。


0


フォーマット文字列は次のアクションを実行します。

  • 1つ以上の「@」以外の文字を読み取る(および破棄する)

  • 0個以上の空白文字を読み取る(および破棄する)(スペースのため) フォーマット文字列内)

  • 1〜8999個の非 `;`文字を読み取って保存する

残念ながら、ユーザー定義セットから「ゼロ以上」の文字を読み取るためのフォーマット指定子はありません。

1行に複数の@includeステートメントが必要ない場合は、コードを変更して(fgetsを使用して)1行を読み取り、そこから@includeステートメントを抽出できます(最初の文字が @`と等しくない場合) 、現在のフォーマット文字列をsscanfで使用できます。そうでない場合は、 `sscanf(line、"%8999 [^;] "、buffer))を使用できます。

1行の複数の@includeステートメンを正しく処理する必要がある場合は、 getc`を使用して次の文字を読み取り、 ungetc`を使用して戻すことができます。