- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在将以下格式的行存储到一个字符中。每个单词由一个表格分隔。
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、CIPHER 和 ESSID 字段。我的最终目标是将每一行的字段存储在一个字符数组中,以便更舒适地使用它们。像这样:
char fields[] = { BSSID, CH,CIPHER, ESSID}
现在我正在使用strtok,以便拆分char 的\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;
}
}
}
最佳答案
您使用 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 读入 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
所做的一样在开关语句中。但这需要直接指向类似 &row.rssid
的东西.也许这对你来说就足够了(我想我已经提供了足够多的东西)。
但公平地说,我会指出这个选项,它可能比使用 memcpy
更简单如上。我会加入 strncpy
我一直在避免的事情。
struct row_data row;
struct column_map {
const char * name;
char *target;
size_t target_size;
int index;
} columns = {
{ "RSSID", row.rssid, sizeof(row.rssid), -1 },
{ "CH", row.ch, sizeof(row.ch), -1 },
{ "CIPHER", row.cipher, sizeof(row.cipher), -1 },
{ "ESSID", row.essid, sizeof(row.essid), -1 },
{ NULL }
};
/* ::: */
if( map->index == column ) {
strncpy( map->target, token, map->target_size );
map->target[map->target_size-1] = '\0'; /* in case of overflow */
}
关于c - 将字符拆分为 C 中的单词,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41056077/
我是一名优秀的程序员,十分优秀!