2

次の形式の複数行 TSV ファイルがあります。

Type\tBasic Name\tAttribute\tA Long Description\n

ご覧のとおり、基本名と説明の両方にいくつかのスペースを含めることができます。各行を読み込んで要素を抽出しようとしています。今のところ、基本的な名前を抽出するだけに絞り込みました。私の fscanf は次のとおりです。

fscanf(file_in, "%*[^ ]s\t%128[^ ]s\t%*[^ ]s\t%[^ ]s\n", name_string, desc_string);

これは期待どおりに機能せず、エラーを絞り込むのに苦労しています。行を正しく読み取る方法を知っている人はいますか?

4

3 に答える 3

3

私はおおむね Pablo に同意します (ファミリーは優れたパーサーを作成しないという点です) が、パターンscanfの書き方を理解することは価値があります。scanf探しているパターンは次のようなものです。

fscanf(" %*[^\t] %128[^\t] %*[^\t] %128[^\n]", name_string, desc_string)

ノート:

  1. %[xyz]ディレクティブです。%[xyz]s2 つのディレクティブで、2 番目のディレクティブはリテラルに一致しますs

  2. 私の知る限り、単一のリテラル タブ文字に一致する方法はありません。これは、パターン内の空白が入力内の任意の量の空白 (なしを含む) と一致するためです。私の例ではスペースを使用しました。これは終了タブに一致しますが、任意の数の連続するタブにも一致するため、空のフィールドは正しく解析されません。

  3. 128 文字の制限には、終端の NUL 文字は含まれません。

  4. また、文字制限を超えてスキャンが停止した場合、残りのフィールドは自動的にスキップされないため、入力と同期しなくなります。

より良いパターンは次のとおりです。

fscanf(" %*[^\t] %128[^\t]%*[^\t] %*[^\t] %128[^\n]%*[^\n]", name_string, desc_string)

必要に応じて、フィールド内の残りの文字を明示的にスキップします。さらに良い解決策は、a修飾子を使用してメモリを取得fscanfすることです。malloc

于 2012-10-10T23:47:48.470 に答える
2

むしろこれに使いたいstrtok。この関数ファミリは、形式が 100% OK の場合にのみ機能するため、より正確fscanfです。それ以外の場合は、値が欠落してしまいます。

Parallel to PHP's " explode " in C: Split char* into char* using delimiterを見てstrtokください。

したがって、各行を で読み取り、fgetsで解析しstrtokます。

于 2012-10-10T23:39:09.547 に答える
0

まず、すでに述べたように、%[]はそれ自体が変換指定子です。s後はありません[]。フォーマット文字列に含まれるs-esは、変換指定子の一部とは見なされません。sあなたはそれらの-esを取り除く必要があります。

次に、あなたが自分で言ったように、ファイルはTABで区切られています。%[^\t]これは、変換指定子(または%[^\n]最後の部分の指定子)を使用して、シーケンスの連続部分を抽出する必要があることをすぐに意味します。なぜ使用%[^ ]し、どのように機能することを期待しましたか?実際には、スペース文字で解析を停止します。%[^ ]これは、必要なものとは逆です。

あなたの例では、指定子の適切な組み合わせは次のようになります。

fscanf(file_in, "%*[^\t]\t%128[^\t]\t%*[^\t]\t%[^\n]\n", name_string, desc_string);

このフォーマット文字列は、文字列の4つの部分すべてが存在することが保証され、最後の部分が。で終了することが保証されていることを前提としています\n

于 2012-10-10T23:59:37.517 に答える