在 C 中使用 strok 解析 NMEA 字符串
Parsing a NMEA String using strok in C
我正在尝试使用带分隔符 "," 的 strtok 函数解析 GNRMC 字符串,当我注意到一些我没有预料到的不同时,一切都很顺利。
如果 String 包含连续的 "," 然后 strtok overshooting 和错位真实数据的打印函数,我的目标是在没有数据时打印 Number 0在连续 ","
之间可用
我该怎么做?
这是我的代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char str[] = "$GPRMC,105954.000,A,3150.6731,N,11711.9399,E,0.00,96.10,250313,,,A*53";
char* Message_ID = strtok(str,",");
char* Time = strtok(NULL,",");
char* Data_Valid = strtok(NULL,",");
char* Raw_Latitude = strtok(NULL,",");
char* N_S = strtok(NULL,",");
char* Raw_Longitude = strtok(NULL,",");
char* E_W = strtok(NULL,",");
char* Speed = strtok(NULL,",");
char* COG = strtok(NULL,",");
char* Date = strtok(NULL,",");
char* Magnetic_Variation = strtok(NULL,",");
char* M_E_W = strtok(NULL,",");
char* Positioning_Mode = strtok(NULL,",");
double Latitude = atof(Raw_Latitude);
double Longitude = atof(Raw_Longitude);
printf("The Message ID is : %s\n", Message_ID);
printf("The Time is : %s\n", Time);
printf("The data valid is : %s\n", Data_Valid);
printf("The Latitude is : %f\n", Latitude);
printf("The N_S is : %s\n", N_S);
printf("The Longitude is : %f\n", Longitude);
printf("The E_W is : %s\n", E_W);
printf("The Speed is : %s\n", Speed);
printf("The COG is : %s\n", COG);
printf("The Date is : %s\n", Date);
printf("The Magnetic_Variation is : %s\n", Magnetic_Variation);
printf("The M_E_W is : %s\n", M_E_W);
printf("The Positioning_Mode is : %s\n", Positioning_Mode);
return 0;
}
输出Window
如果您仅检测到 一个特定字符(如 ','
),直接的方法是使用旧的 strchr()
.
char str[] =
"$GPRMC,105954.000,A,3150.6731,N,11711.9399,E,0.00,96.10,250313,,,A*53";
char* message_id = str;
char* time = strchr(message_id, ','); *time = '[=10=]'; ++time;
char* data_valid = strchr(time,","); *data_valid = '[=10=]'; ++data_valid;
char* raw_latitude = strchr(data_valid,","); *raw_latitude = '[=10=]'; ++raw_latitude;
...
一个棘手的宏可以简化使用:
#define FIND_AND_NUL(s, p, c) ( \
(p) = strchr(s, c), \
*(p) = '[=11=]', \
++(p), \
(p))
这样使用:
char str[] =
"$GPRMC,105954.000,A,3150.6731,N,11711.9399,E,0.00,96.10,250313,,,A*53";
char* message_id = str;
char* time = FIND_AND_NUL(message_id, time, ',');
char* data_valid = FIND_AND_NUL(time, data_valid, ',');
char* raw_latitude = FIND_AND_NUL(data_valid, raw_latitude, ',');
...
我用的是自己的strtok函数,很简单,但是和原来的有两点不同:(1)
分隔符只是单个字符而不是字符串 (2) 如果要解析的字符串有两个连续的分隔符,函数 returns 一个空的非 NULL 标记 ""。这对于解析NMEA报文非常方便
char *strtok_fr (char *s, char delim, char **save_ptr)
{
char *tail;
char c;
if (s == NULL) {
s = *save_ptr;
}
tail = s;
if ((c = *tail) == '[=10=]') {
s = NULL;
}
else {
do {
if (c == delim) {
*tail++ = '[=10=]';
break;
}
}while ((c = *++tail) != '[=10=]');
}
*save_ptr = tail;
return s;
}
非递归版本:
char *strtok_f (char *s, char delim)
{
static char *save_ptr;
return strtok_fr (s, delim, &save_ptr);
}
因此,您的示例(注意“,”而不是“,”分隔符和 strtok_f 而不是 strtok 函数):
int main (int argc, char *argv[])
{
char str[] = "$GPRMC,105954.000,A,3150.6731,N,11711.9399,E,0.00,96.10,250313,,,A*53";
char* Message_ID = strtok_f(str,',');
char* Time = strtok_f(NULL,',');
char* Data_Valid = strtok_f(NULL,',');
char* Raw_Latitude = strtok_f(NULL,',');
char* N_S = strtok_f(NULL,',');
char* Raw_Longitude = strtok_f(NULL,',');
char* E_W = strtok_f(NULL,',');
char* Speed = strtok_f(NULL,',');
char* COG = strtok_f(NULL,',');
char* Date = strtok_f(NULL,',');
char* Magnetic_Variation = strtok_f(NULL,',');
char* M_E_W = strtok_f(NULL,',');
char* Positioning_Mode = strtok_f(NULL,',');
double Latitude = atof(Raw_Latitude);
double Longitude = atof(Raw_Longitude);
printf("The Message ID is : %s\n", Message_ID);
printf("The Time is : %s\n", Time);
printf("The data valid is : %s\n", Data_Valid);
printf("The Latitude is : %f\n", Latitude);
printf("The N_S is : %s\n", N_S);
printf("The Longitude is : %f\n", Longitude);
printf("The E_W is : %s\n", E_W);
printf("The Speed is : %s\n", Speed);
printf("The COG is : %s\n", COG);
printf("The Date is : %s\n", Date);
printf("The Magnetic_Variation is : %s\n", Magnetic_Variation);
printf("The M_E_W is : %s\n", M_E_W);
printf("The Positioning_Mode is : %s\n", Positioning_Mode);
return 0;
}
现在结果:
The Message ID is : $GPRMC
The Time is : 105954.000
The data valid is : A
The Latitude is : 3150.673100
The N_S is : N
The Longitude is : 11711.939900
The E_W is : E
The Speed is : 0.00
The COG is : 96.10
The Date is : 250313
The Magnetic_Variation is :
The M_E_W is :
The Positioning_Mode is : A*53
C:\Users\froca\Desktop\strtok>
请注意 "Magnetic Variation" 和 "M_E_W" 现在是空标记。这就是关键。
我正在尝试使用带分隔符 "," 的 strtok 函数解析 GNRMC 字符串,当我注意到一些我没有预料到的不同时,一切都很顺利。 如果 String 包含连续的 "," 然后 strtok overshooting 和错位真实数据的打印函数,我的目标是在没有数据时打印 Number 0在连续 ","
之间可用我该怎么做?
这是我的代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char str[] = "$GPRMC,105954.000,A,3150.6731,N,11711.9399,E,0.00,96.10,250313,,,A*53";
char* Message_ID = strtok(str,",");
char* Time = strtok(NULL,",");
char* Data_Valid = strtok(NULL,",");
char* Raw_Latitude = strtok(NULL,",");
char* N_S = strtok(NULL,",");
char* Raw_Longitude = strtok(NULL,",");
char* E_W = strtok(NULL,",");
char* Speed = strtok(NULL,",");
char* COG = strtok(NULL,",");
char* Date = strtok(NULL,",");
char* Magnetic_Variation = strtok(NULL,",");
char* M_E_W = strtok(NULL,",");
char* Positioning_Mode = strtok(NULL,",");
double Latitude = atof(Raw_Latitude);
double Longitude = atof(Raw_Longitude);
printf("The Message ID is : %s\n", Message_ID);
printf("The Time is : %s\n", Time);
printf("The data valid is : %s\n", Data_Valid);
printf("The Latitude is : %f\n", Latitude);
printf("The N_S is : %s\n", N_S);
printf("The Longitude is : %f\n", Longitude);
printf("The E_W is : %s\n", E_W);
printf("The Speed is : %s\n", Speed);
printf("The COG is : %s\n", COG);
printf("The Date is : %s\n", Date);
printf("The Magnetic_Variation is : %s\n", Magnetic_Variation);
printf("The M_E_W is : %s\n", M_E_W);
printf("The Positioning_Mode is : %s\n", Positioning_Mode);
return 0;
}
输出Window
如果您仅检测到 一个特定字符(如 ','
),直接的方法是使用旧的 strchr()
.
char str[] =
"$GPRMC,105954.000,A,3150.6731,N,11711.9399,E,0.00,96.10,250313,,,A*53";
char* message_id = str;
char* time = strchr(message_id, ','); *time = '[=10=]'; ++time;
char* data_valid = strchr(time,","); *data_valid = '[=10=]'; ++data_valid;
char* raw_latitude = strchr(data_valid,","); *raw_latitude = '[=10=]'; ++raw_latitude;
...
一个棘手的宏可以简化使用:
#define FIND_AND_NUL(s, p, c) ( \
(p) = strchr(s, c), \
*(p) = '[=11=]', \
++(p), \
(p))
这样使用:
char str[] =
"$GPRMC,105954.000,A,3150.6731,N,11711.9399,E,0.00,96.10,250313,,,A*53";
char* message_id = str;
char* time = FIND_AND_NUL(message_id, time, ',');
char* data_valid = FIND_AND_NUL(time, data_valid, ',');
char* raw_latitude = FIND_AND_NUL(data_valid, raw_latitude, ',');
...
我用的是自己的strtok函数,很简单,但是和原来的有两点不同:(1) 分隔符只是单个字符而不是字符串 (2) 如果要解析的字符串有两个连续的分隔符,函数 returns 一个空的非 NULL 标记 ""。这对于解析NMEA报文非常方便
char *strtok_fr (char *s, char delim, char **save_ptr)
{
char *tail;
char c;
if (s == NULL) {
s = *save_ptr;
}
tail = s;
if ((c = *tail) == '[=10=]') {
s = NULL;
}
else {
do {
if (c == delim) {
*tail++ = '[=10=]';
break;
}
}while ((c = *++tail) != '[=10=]');
}
*save_ptr = tail;
return s;
}
非递归版本:
char *strtok_f (char *s, char delim)
{
static char *save_ptr;
return strtok_fr (s, delim, &save_ptr);
}
因此,您的示例(注意“,”而不是“,”分隔符和 strtok_f 而不是 strtok 函数):
int main (int argc, char *argv[])
{
char str[] = "$GPRMC,105954.000,A,3150.6731,N,11711.9399,E,0.00,96.10,250313,,,A*53";
char* Message_ID = strtok_f(str,',');
char* Time = strtok_f(NULL,',');
char* Data_Valid = strtok_f(NULL,',');
char* Raw_Latitude = strtok_f(NULL,',');
char* N_S = strtok_f(NULL,',');
char* Raw_Longitude = strtok_f(NULL,',');
char* E_W = strtok_f(NULL,',');
char* Speed = strtok_f(NULL,',');
char* COG = strtok_f(NULL,',');
char* Date = strtok_f(NULL,',');
char* Magnetic_Variation = strtok_f(NULL,',');
char* M_E_W = strtok_f(NULL,',');
char* Positioning_Mode = strtok_f(NULL,',');
double Latitude = atof(Raw_Latitude);
double Longitude = atof(Raw_Longitude);
printf("The Message ID is : %s\n", Message_ID);
printf("The Time is : %s\n", Time);
printf("The data valid is : %s\n", Data_Valid);
printf("The Latitude is : %f\n", Latitude);
printf("The N_S is : %s\n", N_S);
printf("The Longitude is : %f\n", Longitude);
printf("The E_W is : %s\n", E_W);
printf("The Speed is : %s\n", Speed);
printf("The COG is : %s\n", COG);
printf("The Date is : %s\n", Date);
printf("The Magnetic_Variation is : %s\n", Magnetic_Variation);
printf("The M_E_W is : %s\n", M_E_W);
printf("The Positioning_Mode is : %s\n", Positioning_Mode);
return 0;
}
现在结果:
The Message ID is : $GPRMC
The Time is : 105954.000
The data valid is : A
The Latitude is : 3150.673100
The N_S is : N
The Longitude is : 11711.939900
The E_W is : E
The Speed is : 0.00
The COG is : 96.10
The Date is : 250313
The Magnetic_Variation is :
The M_E_W is :
The Positioning_Mode is : A*53
C:\Users\froca\Desktop\strtok>
请注意 "Magnetic Variation" 和 "M_E_W" 现在是空标记。这就是关键。