2016-12-09 2 views
3

Я сохраняю строки следующего формата в символ. Каждое слово разделяется таблицей.Разделить символ на слова в 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 

Я хочу, чтобы разделить каждую строку (содержащуюся в полукоксе) для того, чтобы получить поля BSSID, CH, шифры и ESSID. Моя конечная цель - сохранить поля каждой строки в массиве символов, чтобы работать с ними более комфортно. Что-то вроде этого:

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

Теперь я использую strtok для того, чтобы расколоть \t полукокса, но это очень неудобно. Следуя здесь, это мой первый подход, но он очень плохой, потому что он фокусируется только на четвертой строке и втором поле. Может кто-нибудь помочь мне с кодом? Я также открылся для другого способа программирования.

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 array» или «string» not «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)); 
     } 
    } 
} 

Вместо сохраняя смещения в таблице, вы могли бы, конечно, сохранить указатель, как и мы с target в инструкции switch. Но это потребовало бы прямого указания на что-то вроде &row.rssid. Возможно, этого достаточно для вас (я подозреваю, что я уже предоставил более чем достаточно).

Но, если быть справедливым, я укажу на этот вариант, который может быть проще, чем использование memcpy, как указано выше. И я буду рулон в strncpy материалах, которых я избегаю.

+0

Что вы здесь делаете: – JoseJ

+0

В третьем поле кода, что вы делаете внутри for с token = strtok (NULL, s)? Если бы я использовал код, который вы написали до третьего кода окна, и не получил ожидаемого результата. Вместо этого в каждом параметре printf я получаю только разрывы \ t строки. Что-то вроде: 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 cipher = 2 0 0 13 54e. WPA2 CCMP PSK xxxx essid = 0 0 13 54e. WPA2 CCMP PSK xxxx – JoseJ

Смежные вопросы