6

次のようなデータを含む CSV ファイルがあります。

value;name;test;etc

を使用して分割しようとしていstrtok(string, ";")ます。ただし、このファイルには、次のような長さ 0 のデータを含めることができます。

value;;test;etc

strtok()スキップします。strtokこのような長さゼロのデータをスキップしないようにする方法はありますか?

4

3 に答える 3

8

strsep()可能であれば、 の代わりにBSD 関数を使用することstrtok()もできます。マニュアルページから:

このstrsep()関数は、関数の代替として意図されていstrtok() ます。このstrtok()関数は移植性の理由から優先されるべきですが (ISO/IEC 9899:1990 ("ISO C90") に準拠しています)、空のフィールドを処理することはできません。つまり、2 つの隣接する区切り文字で区切られたフィールドを検出したり、一度に複数の文字列。このstrsep()関数は、4.4BSD で初めて登場しました。

簡単な例 (これも man ページからコピー):

char *token, *string, *tofree;

tofree = string = strdup("value;;test;etc");
while ((token = strsep(&string, ";")) != NULL)
    printf("token=%s\n", token);

free(tofree);

出力:

トークン=値
トークン=
トークン=テスト
トークン=など

そのため、空のフィールドは正しく処理されます。

もちろん、他の人が言ったように、これらの単純なトークナイザー関数は引用符内の区切り文字を正しく処理しないため、それが問題になる場合は、適切なCSV 解析ライブラリを使用する必要があります。

于 2013-09-16T12:50:44.957 に答える
4

このように動作しないようにする方法はありませstrtok()ん。マンページから:

解析された文字列内の連続する 2 つ以上の区切り文字バイトのシーケンスは、単一の区切り文字と見なされます。文字列の先頭または末尾の区切り文字バイトは無視されます。別の言い方をすれば、 strtok() によって返されるトークンは常に空でない文字列です。

ただし、検出されたすべてのトークンを に置き換えるため、できること'\0'は、トークンの前の文字数を確認することです。そうすれば、スキップされたトークンの数がわかります。ソース情報:strtok()'\0'

このトークンの末尾は自動的にヌル文字に置き換えられ、トークンの先頭が関数によって返されます。

そして、私が何を意味するかを示すコードサンプル。

char* aStr = ...;
char* ptr = NULL;

ptr = strtok (...);

char* back = ptr;
int count = -1;
do {
  back--;
  if (back <= aStr) break; // to protect against reads before aStr
  count++;
} while (*back = '\0');

(ide またはテストなしで記述されたものは、無効な実装である可能性がありますが、アイデアは有効です)。

于 2013-09-16T12:12:01.110 に答える
2

いいえ、できません。「男strtok」より:

解析された文字列内の 2 つ以上の連続する区切り文字のシーケンスは、単一の区切り文字と見なされます。文字列の先頭または末尾の区切り文字は無視されます。別の言い方をすれば、 strtok() によって返されるトークンは常に空でない文字列です。

データに引用符内の区切り文字またはその他の「エスケープ」が含まれている場合にも、問題が発生する可能性があります。

最善の解決策は、CSV 解析ライブラリを入手するか、独自の解析関数を作成することだと思います。

于 2013-09-16T12:14:04.373 に答える