在 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" 现在是空标记。这就是关键。