我目前正在为 nmea 句子开发一个解析器,通常是这样的:
"$GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62\r\n"
所以我创建了这个函数,它使用 strtok 来解析它,使用逗号作为分隔符并将每个数据字段存储在值数组中,重要的是每个数据字段都进入数组中的正确位置。
int split_string_by_comma (nmea_message_t * message_info, char ** values)
{
int i = 0;
char * p = strtok(message_info->data_field, MSG_DELIMITER);
while (p != NULL)
{
values[i++] = p;
p = strtok(NULL, MSG_DELIMITER);
}
return i;
}
问题是,nmea 语句跳过某些数据字段的情况并不少见,例如:
"$GPRMC,,A,,S,14507.36,E,000.0,,,,E*62\r\n"
在这种情况下,我的函数是无用的,因为我希望逗号之间的空数据字段被分配为 NULL 值,而不是被完全忽略。
有什么建议吗? 谢谢!
strsep
可能是你想要的:
引入 strsep() 函数作为 strtok(3) 的替代品,
因为后者不能处理空字段。
然而,strtok(3) 符合 C89/C99,因此更便携。
它的语法不完全一样:
#include <stdio.h>
#include <string.h>
#define MSG_DELIMITER ","
void split_string_by_comma (char* msg)
{
int i = 0;
char * p = strsep(&msg, MSG_DELIMITER);
while (p != NULL)
{
printf("%d - %s\n", ++i, p);
p = strsep(&msg, MSG_DELIMITER);
}
}
int main(void)
{
char good[] = "$GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62\r\n";
char bad[] = "$GPRMC,,A,,S,14507.36,E,000.0,,,,E*62\r\n";
split_string_by_comma(good);
split_string_by_comma(bad);
return 0;
}
:~/test/strsep$ ./a.out
1 - $GPRMC
2 - 081836
3 - A
4 - 3751.65
5 - S
6 - 14507.36
7 - E
8 - 000.0
9 - 360.0
10 - 130998
11 - 011.3
12 - E*62
1 - $GPRMC
2 -
3 - A
4 -
5 - S
6 - 14507.36
7 - E
8 - 000.0
9 -
10 -
11 -
12 - E*62
这是
strsep()
的替代方案,我正在开发一个不可用的系统。使用 strtok_r()
来自上一个调用的剩余指针地址和从当前调用开始的标记化地址可以识别是否跳过了任何额外的定界符。
#include <stdio.h>
#include <string.h>
#define MAX_TOKENS 15
#define MAX_TOKEN_LEN 20
int main()
{
char tokens[MAX_TOKENS][MAX_TOKEN_LEN] = { 0 };
char str[] = "This,is,a,string,,to,be,,,split,on,comma";
char *leftover;
unsigned long leftover_addr_start = (unsigned long)str; // Save leftover start
const char *token = strtok_r(str, ",", &leftover);
int total_tokens = 0;
do {
unsigned long token_addr = (unsigned long)token; // Token start address
if(token_addr != leftover_addr_start) { // Extra delimiters encountered
unsigned long num_extra_delm =
(unsigned long)(token_addr - leftover_addr_start);
printf("%lu Extra delimiter(s) encountered between '%s' and '%s'\n",
num_extra_delm, tokens[total_tokens-1], token);
}
(void)strncpy(tokens[total_tokens], token, MAX_TOKEN_LEN); // Save Token
printf("Tokenized - '%s'\n", tokens[total_tokens]);
total_tokens++; // Increase Token count
leftover_addr_start = (unsigned long)leftover; // Save leftover start address
} while((token = strtok_r(NULL, ",", &leftover)) && total_tokens < MAX_TOKENS);
return 0;
}