将char分成C中的单词

时间:2016-12-09 08:26:32

标签: c linux string

我将以下格式的行存储到char中。每个单词由制表分隔。

unmanaged

我想分割每一行(包含在char中)以获取字段BSSID,CH,CIPHER和ESSID。我的最终目标是将每行的字段存储在一组字符中,以便更舒适地使用它们。像这样:

managed

现在我正在使用 strtok ,以便分割char的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 ,但这非常不舒服。这是我的第一种方法,但是非常糟糕,因为它只关注第四线和第二场。任何人都可以帮我代码吗?我也接受了不同的编程方式。

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

2 个答案:

答案 0 :(得分: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的参数(我的例子很简短,使用{{1} })。或者您可以采用不同的方向并仅在结构中存储指针。然后,您可以使用动态分配来复制字符串。

现在,如果您的列顺序未知,那么您必须进一步抽象这一步。这将首先阅读标题行并查找您感兴趣的部分,并存储它们出现的列索引。这会使你的代码变得更复杂,但并非不合理。

起点可能是这个(需要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

当然,您可以存储指针,而不是在表中存储偏移量,就像我们在switch语句中使用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之类的东西。也许这对你来说足够了(我怀疑我已经提供了足够多的东西)。

但公平地说,我会指出这个选项,这可能比上面使用&row.rssid更简单。而且我会在我不断避免的memcpy内容中滚动。

strncpy

答案 1 :(得分:2)

一个简单的伎俩:

考虑到您的“字词”中没有任何空格,您可以使用sscanf

此功能允许您从字符串而不是stdin读取值。如果它们之间有任何空格,则会自动将它们解析为单独的值。您可以忽略您不想阅读的值。

示例:

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

%*s将读取一个字段,但不会将其分配给任何变量。因此,只需将所需的字段分配给变量。

您必须为输出中的每一行运行此语句。