使用C中的strok解析NMEA字符串

时间:2018-01-28 13:37:59

标签: c string parsing delimiter

我正在尝试使用带有分隔符"" 的strtok函数来解析GNRMC字符串,当我注意到一些我不期待的不同时,一切都很顺利。 如果String包含连续的" ,," ,那么strtok过冲和打印功能错误地放置了真实数据,我的目标是在那里&#39时打印数字 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;
}

输出窗口 Output Window

2 个答案:

答案 0 :(得分:2)

如果您仅检测到一个特定字符(例如','),那么直接的方法就是使用旧的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 = '\0'; ++time;
 char* data_valid = strchr(time,","); *data_valid = '\0'; ++data_valid;
 char* raw_latitude = strchr(data_valid,","); *raw_latitude = '\0'; ++raw_latitude;
 ...

棘手的宏可以简化使用:

#define FIND_AND_NUL(s, p, c) ( \
   (p) = strchr(s, c), \
   *(p) = '\0', \
   ++(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, ',');
 ...

答案 1 :(得分:1)

我使用自己的strtok函数,该函数非常简单,但与原始函数有两个区别:(1) 如果要解析的字符串具有两个连续的定界符,则定界符仅是单个字符,而不是字符串(2),该函数将返回一个空的非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) == '\0') {
        s = NULL;
    }
    else {
        do {
            if (c == delim) {
                *tail++ = '\0';
                break;
           }
        }while ((c = *++tail) != '\0');
    }
    *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;
}

现在的结果:

消息ID为:$ GPRMC
时间是:105954.000
有效数据为:A
纬度为:3150.673100
N_S是:N
经度是:11711.939900
E_W是:E
速度为:0.00
COG为:96.10
日期是:250313
Magnetic_Variation为:
M_E_W是:
Positioning_Mode为:A * 53

C:\ Users \ froca \ Desktop \ strtok>

请注意,“磁变”和“ M_E_W”现在是空标记。那是关键。