我将以下格式的行存储到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}
答案 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
将读取一个字段,但不会将其分配给任何变量。因此,只需将所需的字段分配给变量。
您必须为输出中的每一行运行此语句。