2016-12-09 7 views
3

私は次の形式の行をcharに格納しています。各単語は集計によって区切られています。C言語で単語を分割する

BSSID    PWR Beacons #Data, #/s CH MB ENC CIPHER AUTH ESSID 
00:34:34:34:34:34 -56  9  0 0 11 54e. WPA2 CCMP PSK wifi_id 
00:44:44:44:44:34 -56  9  0 0 11 54e. WPA2 CCMP PSK wifi_id2 
00:54:54:54:54:54 -56  9  0 0 11 54e. WPA2 CCMP PSK wifi_id3 

IフィールドBSSID、CH、CIPHERとESSIDを取得するために(チャーに含まれる)各ラインを分割します。私の最終的な目標は、各行のフィールドをcharの配列に格納して、より快適に作業できるようにすることです。このような何か:

char fields[] = { BSSID, CH,CIPHER, ESSID} 

今私がcharの\tを分割するためには、はstrtokを使用していますが、これは非常に不快です。ここに続くのは私の最初のアプローチですが、それは第4ラインと第2フィールドだけに焦点を当てるので非常に貧しいです。誰でもコードを教えてくれますか?私はまた、それをプログラミングする別の方法にもオープンしています。

const char s[2]= "\t"; 
while (fgets(path, sizeof(path)-1, fp) != NULL) { 
    i = i + 1; 
    if (i == 4){ 
    token = strtok(path, s); 
    /* walk through other tokens */ 
    while(token != NULL) 
    { 
     token = strtok(NULL, s); 
     strncpy(field2, token, 18); 
     break; 
    } 
    } 
} 
+1

「char配列」または「文字列」は「char」ではなく「charを単語に分割する」という意味は、はっきりとは異なる意味を持ちます。 – spinkus

答えて

2

簡単なトリック:

あなたの「言葉」はその中の任意の空白スペースを持っていないことを考えると、あなたはsscanfを使用することができます。

この関数を使用すると、stdinの代わりに文字列から値を読み取ることができます。これらは、それらの間に空白がある場合、別々の値として自動的に解析されます。読みたくない値は無視してもかまいません。

例:

sscanf(token, "%s %*s %*s %*s %*s %s %*s %*s %s %*s %s",BSSID, CH, CIPHER, ESSID); 

%*sは、フィールドを読むが、どの変数に代入しません。したがって、必要なフィールドだけが変数に割り当てられます。

このステートメントは、出力のすべての行に実行する必要があります。

3

あなたのアプローチはstrtokで問題ありませんが、おそらくデータを構造体に格納したいことがあります。次のようなもの固定長の文字列の最大長を選択し、それらの文字列を作成しました。

struct row_data { 
    char bssid[18]; 
    char ch[4]; 
    char cipher[10]; 
    char essid[20]; 
}; 

列の順序が正確にわかっている場合は、ここで停止できます。ただ、インデックス列挙の列:このような

enum column_id { 
    COL_RSSID = 0, 
    COL_CH = 5, 
    COL_CIPHER = 8, 
    COL_ESSID = 10 
}; 

そして今、何かがそれを行うだろう:

int column = 0; 
char *target = NULL; 
struct row_data row; 
struct row_data empty_row = {0}; 

while(fgets(path, sizeof(path), fp)) 
{ 
    row = empty_row; 

    token = strtok(path, s); 
    for(column = 0; token; token = strtok(NULL,s), column++) 
    { 
     switch(column) 
     { 
     case COL_RSSID: target = row.rssid; break; 
     case COL_CH:  target = row.ch;  break; 
     case COL_CIPHER: target = row.cipher; break; 
     case COL_ESSID: target = row.essid; break; 
     default:   target = NULL; 
     } 

     if(target) strcpy(target, token); 
    } 

    /* do something with row */ 
    printf("Read rssid=%s ch=%s cipher=%s essid=%s\n", 
      row.rssid, row.ch, row.cipher, row.essid); 
} 

はまた、として使用することができtarget_lengthまたは類似を作るためにあまりにも多くの余分な作業ではありませんパラメータをstrncpyに設定します(私の例は短く、strcpyを使用しています)。または、別の方向に移動し、構造体にポインタのみを格納することもできます。次に、ダイナミックアロケーションを使用して文字列をコピーすることができます。

ここで、列の順序がわからない場合、これをさらに抽象化する必要があります。これは、最初にヘッダー行を読んで、関心のある部分を探し、そこに表示される列インデックスを保存することになります。これはあなたのコードをより複雑にしますが、不合理ではありません。

出発点は、このかもしれません(<stdlib.h>が必要です):

struct column_map { 
    const char * name; 
    size_t offset; 
    int index; 
} columns = { 
    { "RSSID", offsetof(struct row_data, rssid), -1 }, 
    { "CH",  offsetof(struct row_data, ch),  -1 }, 
    { "CIPHER", offsetof(struct row_data, cipher), -1 }, 
    { "ESSID", offsetof(struct row_data, essid), -1 }, 
    { NULL } 
}; 

/* first read the header */ 
token = strtok(header, s); 
for(column = 0; token; token = strtok(NULL,s), column++) 
{ 
    for(struct column_map *map = columns; map->name; map++) { 
     if(map->index == -1 && 0 == strcmp(token, map->name)) { 
      map->index = column; 
     } 
    } 
} 

これが起こっている場所を見ることができます。あなたはheaderにヘッダを読んでいたと仮定すると、今、あなたが興味を持っている各列の列インデックスとcolumnsを埋めそしてているので、他の行を読んだときには、スイッチの代わりにこれを行う:。

row = empty_row; 
token = strtok(path, s); 
for(column = 0; token; token = strtok(NULL,s), column++) 
{ 
    for(struct column_map *map = columns; map->name; map++) { 
     if(map->index == column) { 
      /* again, if using strncpy, store a length inside the map, 
       and use MIN(map->length, strlen(token)+1) or similar */ 
      memcpy((char*)&row + map->offset, token, strlen(token)); 
     } 
    } 
} 

の代わりにテーブルにオフセットを格納すると、もちろんswitch文にtargetと同じようにポインタを格納することができます。しかし、それは直接&row.rssidのようなものを指す必要があります。多分それはあなたのために十分です(私は既に十分以上のものを提供していると思います)。

しかし、私はこのオプションを指摘しますが、これは上記のようにmemcpyを使用するより簡単かもしれません。そして、私が避けているものであるstrncpyのものに巻き込まれます。

+0

ここで何をしていますか: – JoseJ

+0

コードの3番目のボックスで、forトークン= strtok(NULL、s)で何をしていますか?私が3番目のボックスコードまで書いたコードを使用した場合、期待した結果が得られません。代わりに、printfの各パラメタでは、私は行の分割だけを取得します。何かが好きです:rssid = 98:FC:11:A8:7B:67 -64 2 0 0 13 54e。 WPA2 CCMP PSK xxxx ch = -64 2 0 0 13 54e。 WPA2 CCMP PSK xxxx 暗号= 2 0 0 13 54e。 WPA2 CCMP PSK xxxx essid = 0 0 13 54e。 WPA2 CCMP PSK xxxx – JoseJ

関連する問題