2016-03-30 8 views
0

あるフィールドをタブで区切ったファイルがあります。常に17個のタブがありますが、順序があり、このような..Cで連続したタブを認識するための文字列を分割する

75104\tDallas\t85\t34.46\t45.64 
75205\tHouston\t\t37.34\t87.32 
93434\t\t\t1.23\t3.32 

私は、次のファッション

while (fgets(buf, sizeof(buf), fp) != NULL) { 
    tok = strtok(buf,"\t"); 

    while(tok != NULL) { 
     printf("%s->",tok); 
     tok = strtok(NULL,"\t"); 
    } 
} 

strtokを使用する場合、私はすべてのトークンを取得するよう、様々であるが、二重のタブ\t\t以上のことができます無視されます。しかし、フィールドが空の場合は、フィールドが空の場合はプレースホルダを使用して構造が17個のタブに依存するため、フィールドが空のときには、strtokは複数のタブを無視できません。

私は

if(tok == NULL || '') 

での問題に対処しようとしましたが、私はstrtokタブの後にタブを認識しないと思います。この問題に対処する最善の方法は何ですか?

+1

それを見てください - あなたの 'if(tok == NULL || '')'試みはあなたが別の言語に慣れているように見えます。それは技術的には有効ですが、あなたがしたいことはほとんどありません。 – usr2564301

+0

strtok()は使用できません。ステートマシンを構築したり、strspn()/ strcspn()を使用する。 – joop

答えて

2

あなたのケースではstrtokは使用できません。 man strtok:

はstrtok()関数はゼロ以上 空でないトークン の配列に文字列を壊すから ...上記の説明から、2つ以上の 連続区切りバイトのシーケンスに従いますは、 の単一区切り文字とみなされ、 文字列の先頭または末尾の区切り文字は無視されます。言い換えると、strtok()によって返されるトークン は常に空ではない文字列です。たとえば、文字列 "aaa ;; bbb"を指定すると、区切り文字 の文字列 ";"を指定するstrtok()の連続呼び出しでは、文字列 "aaa"および "bbb"が返され、次にNULL ポインタ

それが利用可能な場合あなたは、手動で線形検索とstrncpyを使用する関数を書き、またはsscanfまたはstrsepを使用している可能性のいずれかの選択肢を、見つける必要があります。後者はstrtokを置き換えることを意図しているので、おそらく私の選択になるでしょう。

後者は空のフィールドを扱えないためman strsep:

からstrsep()関数はstrtokの代替(3)、 として導入しました。しかし、strtok(3)はとなり、C89/C99になり、移植性が向上します。

+1

これは、あなたのツールチェーンの一部ではない場合に使用できる 'strsep()'の簡単な実装です:http://stackoverflow.com/a/8514474/12711 –

0

はここで事実に対処するために特別に導入されたstrsepを用いて、溶液、だと連続で区切り文字を超えるstrtokスキップ:

char *cur, *nxt; 
while (fgets(buf, sizeof(buf), fp) != NULL) 
{ 
    nxt = buf; 
    while ((cur = strsep(&nxt, "\t")) != NULL) 
    { 
     printf("%s->",cur); 
    } 
} 

注:特に文字列リテラルを渡すstrsepに渡された文字列を書き込み可能でなければなりません(動作しません)。 strsepによって変更されます(区切り文字は連続する呼び出しでNUL文字で上書きされます)。

0

これを実装する方法を理解するには、以下の関数を使用してください。 :

int splitLine(char *buf, char **argv, int max_args) 
{ 
    int arg; 

    /* skip over initial spaces */ 
    while (isspace(*buf)) buf++; 

    for (arg = 0; arg < max_args 
     && *buf != '\0'; arg++) { 
     argv[arg] = buf; 
     /* skip past letters in word */ 
     while (*buf != '\0' 
      && !isspace(*buf)) { 
      buf++; 
     } 
     /* if not at line's end, mark 
     * word's end and continue */ 
     if (*buf != '\0') { 
      *buf = '\0'; 
      buf++; 
     } 
     /* skip over extra spaces */ 
     while (isspace(*buf)) buf++; 
    } 
    return arg; 
} 

この関数はスペース区切り文字を使用して、他のものを使用するように再実装できます。

関連する問題