比如说我们要做一个GPS导航的项目,需要读取GPS模块以ASCII码的形式发送过来的数据,然后对这些数据进行处理,提取我们需要的信息。这就涉及到很多操作字符串的问题。下面就以此为例,利用strstr函数和sscanf函数解析GPS数据。

GPS输出的数据格式如下:
$GPGGA,121252.000,3937.3032,N,11611.6046,E,1,05,2.0,45.9,M,-5.7,M,,0000*77 
$GPRMC,121252.000,A,3958.3032,N,11629.6046,E,15.15,359.95,070306,,,A*54 
$GPVTG,359.95,T,,M,15.15,N,28.0,K,A*04 
$GPGGA,121253.000,3937.3090,N,11611.6057,E,1,06,1.2,44.6,M,-5.7,M,,0000*72 
$GPGSA,A,3,14,15,05,22,18,26,,,,,,,2.1,1.2,1.7*3D 
$GPGSV,3,1,10,18,84,067,23,09,67,067,27,22,49,312,28,15,47,231,30*70 
$GPGSV,3,2,10,21,32,199,23,14,25,272,24,05,21,140,32,26,14,070,20*7E 
$GPGSV,3,3,10,29,07,074,,30,07,163,28*7D

可以看到,GPS模块发送过来的原始数据有很多,但是通常我们只需要其中的一部分信息就够用了,比如对于导航的功能,我们只需要以$GPRMC开头,以换行符结束的一行信息就够了。即:
$GPRMC,121252.000,A,3958.3032,N,11629.6046,E,15.15,359.95,070306,,,A*54

因此我们需要做的就是从读取的数据中截取以$GPRMC开头的一行信息,然后从中解析出经纬度、日期时间等有效信息即可。

假设从串口读取的数据存放在一个字符串指针char *raw_buf指向的内存单元里,首先我们通过ANSI C提供的strstr()函数找到以$GPRMC开头以换行符’\n’结束的字符串:
/* find "$GPRMC" from raw_buf */
if ((wellhandled_string = strstr(raw_buf, “$GPRMC”)) != NULL)
{
        for (i=0; i<strlen(wellhandled_string); i++)
        {
                if (wellhandled_string[i] == '\n')
                {
                        wellhandled_string[i] = '\0'; //replace ‘\n’ with null
                }
        } 
}
strstr()函数的原型是这样声明的:
char *strstr(const char *haystack, const char *needle);

strstr()函数可以在字符串haystack中搜索字符串needle第一次出现的位置,并且返回指向字符串needle首地址的指针,如果没有搜索到则返回NULL。因此上面的代码为我们在读取的原始数据raw_buf里搜索$GPRMC第一次出现的位置,并将返回的指针赋给wellhandled_string,这样如果搜索成功,则wellhandled_string就会指向以$GPRMC开始的字符串,接下来通过一个for循环找到换行符’\n’,将其替换为’\0’,即字符串结束符。这样就得到了一个指向有效数据的字符串指针wellhandled_string。

然后要做的工作就是从wellhandled_string中提取出经纬度、日期时间等信息。这个工作就可以交给强大的sscanf函数来实现。sscanf函数的原型如下:
int sscanf(const char *str, const char *format, ...);

我们都比较熟悉scanf这个函数,scanf可以从标准输入流读取与指定格式相符的数据。sscanf则是从const char
*str中读取。它的强大之处在于可以方便地从字符串中取出整数、浮点数和字符串等各种类型的数据,而且它还具有类似于正则表达式的匹配功能,sscanf默认是以空格分隔字符串的,如果不是以空格来分割的话,就可以使用%[

]来指定分割的条件。如%[a-z]表示读取a到z的所有字符,%[^a-z]表示过滤a-z之间的所有字符,即只要遇到a到z之间的任意字符,转换立刻停止。比如:
sscanf(“abcdefABCDEF”, “%[^A-Z]”, str);
printf(“%s\n”, str);
result is: abcdef
%[^A-Z]这样的匹配格式为我们取遇到大写字母为止的字符串。利用这种匹配方式,我们就可以灵活的操作字符串,得到我们想要的结果。

现在我们需要从下面的字符串中提取有效信息:
$GPRMC,121252.000,A,3958.3032,N,11629.6046,E,15.15,359.95,070306,,,A*54

GPRMC每个字段的含义如下:

$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh<CR><LF> 
<1> UTC时间,hhmmss(时分秒)格式 
<2> 定位状态,A=有效定位,V=无效定位 
<3> 纬度ddmm.mmmm(度分)格式(前面的0也将被传输) 
<4> 纬度半球N(北半球)或S(南半球) 
<5> 经度dddmm.mmmm(度分)格式(前面的0也将被传输) 
<6> 经度半球E(东经)或W(西经) 
<7> 地面速率(000.0~999.9节,前面的0也将被传输) 
<8> 地面航向(000.0~359.9度,以真北为参考基准,前面的0也将被传输) 
<9> UTC日期,ddmmyy(日月年)格式 
<10> 磁偏角(000.0~180.0度,前面的0也将被传输) 
<11> 磁偏角方向,E(东)或W(西) 
<12> 模式指示(仅NMEA0183 3.00版本输出,A=自主定位,D=差分,E=估算,N=数据无效)

我们提取1~9九条信息。用一个结构体存放这些信息:
typedef struct gps_info
{
        char utc_time[BUF_SIZE];
        char status;
        float latitude_value;
        char latitude;
        float longtitude_value;
        char longtitude;
        float speed;
        float azimuth_angle;
        char utc_data[BUF_SIZE];
}GPS_INFO;

因为每一个字段之间都是以逗号间隔开的,所以我们可以利用%[^,]来分割字符串,这样用sscanf函数就可以实现对有效信息的提取:
sscanf(wellhandled_string,"$GPRMC,%[^,],%c,%f,%c,%f,%c,%f,%f,%[^,]", 
            rmc_info->utc_time,\
            &(rmc_info->status),&(rmc_info->latitude_value),&(rmc_info->latitude),\
            &(rmc_info->longtitude_value),&(rmc_info->longtitude),&(rmc_info->speed),\
            &(rmc_info->azimuth_angle),\
            rmc_info->utc_data );
这个函数执行后,打印出的保存在struct gps_info结构体里的信息如下所示:
utc_time: 024813.640
status: A
latitude: N latitude value: 3158.460693
longtitude: E longtitude value: 11848.374023
speed: 10.050000
azimuth_angle: 324.269989
utc_data: 150706

可见,利用好sscanf函数,可以让我们可以很高效的处理字符串。

利用strstr和sscanf解析GPS信息的更多相关文章

  1. 使用SerialPort 读取外置GPS信息和使用GeoCoordinateWatcher获取内置gps的信息

    简介最近工作中需要读取gps设备的信息,平板本身有内置的gps设备,但是精度不够,就又添加了一个外置的gps.对于外置的gps,我们主要通过SerialPort类来获得串口的信息,然后对接收到的内容进 ...

  2. 对于接收到的GPS信息详解

    最近一直在做gps驱动方面的东西,对于底层接收到的gps信息不是很了解,查询了资料对这些信息做出总结: 由于在室内,所以信号不是很好,接收不到卫星信号,必须站到窗口或者空旷的地方,这是gps的debu ...

  3. 照片 GPS 信息查询

    照片 GPS 信息查询 经纬度查询 https://jingweidu.51240.com/ // 30.27832833333333, 120.01914111111111 30 + 16/60 + ...

  4. 温故知新,.Net Core利用UserAgent+rDNS双解析方案,正确识别并反爬虫/反垃圾邮件

    背景 一般有价值的并保有数据的网站或接口很容易被爬虫,爬虫会占用大量的流量资源,接下来我们参考历史经验,探索如何在.Net Core中利用UserAgent+rDNS双解析方案来正确识别并且反爬虫. ...

  5. 文件读写以及NMEA码中GPS信息的提取

    首先先了解下什么是NMEA码,这里有很好的解释,就不直接搬运了 http://www.gpsbaby.com/wz/nmea.html 首先要找到包含GPS信息的文本行,即字符串GPGGA所在行 $G ...

  6. php 解析 视频 信息 封面 标题 图片 支持 优酷, 土豆 酷6 56 新浪 qq播客 乐视 乐视

    原文地址:http://www.lianyue.org/2013/2497/ <?php /** * 解析 视频信息 类 * * 支持 优酷, 土豆 酷6 56 新浪 qq播客 乐视 乐视 ** ...

  7. 使用htmlunit在线解析网页信息

    前言 最近工作上遇到一个问题,后端有一个定时任务,需要用JAVA每天判断法定节假日.周末放假,上班等情况, 其实想单独通过逻辑什么的去判断中国法定节假日的放假情况,基本不可能,因为国家每一年的假期可能 ...

  8. Java下利用Jackson进行JSON解析和序列化

    Java下利用Jackson进行JSON解析和序列化   Java下常见的Json类库有Gson.JSON-lib和Jackson等,Jackson相对来说比较高效,在项目中主要使用Jackson进行 ...

  9. python利用or在列表解析中调用多个函数.py

    python利用or在列表解析中调用多个函数.py """ python利用or在列表解析中调用多个函数.py 2016年3月15日 05:08:42 codegay & ...

随机推荐

  1. LeetCode——15. 3Sum

    一.题目链接:https://leetcode.com/problems/3sum/ 二.题目大意: 3和问题是一个比较经典的问题,它可以看做是由2和问题(见http://www.cnblogs.co ...

  2. 阿里云服务器 ECS Linux SWAP 配置概要说明

    SWAP 简介 Linux 中的 SWAP(交换分区),类似于 Windows 的虚拟内存.系统会把一部分硬盘空间虚拟成内存使用,将系统内非活动内存换页到 SWAP,以提高系统可用内存. 注:参阅 E ...

  3. spring boot学习(8) SpringBoot 之切面AOP

    在方法执行的前后,切入代码:经典的service层切入事务: @Aspect注解是切面注解类 @Pointcut切点定义 @Before是方法执行前调用 @After是方法执行后调用 @AfterRe ...

  4. 网站首页多URL可访问,如何集中首页网站权重?

    原文地址:http://ask.seowhy.com/question/8573 百度站长平台Lee在文章<建立符合搜索引擎抓取习惯>一文中提出:唯一性网站中同一内容页只与唯一一个url相 ...

  5. php安装imagemagick扩展 常见问题与解决方案(win平台)

    1.写在前面 1-1.ImageMagick介绍 ImageMagick是一套功能强大.稳定而且开源的工具集和开发包,可以用来读.写和处理超过89种基本格式的图片文件,包括流行的TIFF.JPEG.G ...

  6. eclipse调试的时候怎么后退?

    原文转载至:https://blog.csdn.net/qq_21262611/article/details/52121270 个人分类: myeclipse   前些天和同事交流调试技巧时,知道了 ...

  7. Map相关问题

    <!--加载地图开始--> <!DOCTYPE html><html><head> <meta charset="UTF-8" ...

  8. SQL按分隔符拆分字段串

    CREATE VIEW [dbo].[Split_BusinessUnit] AS WITH tt AS ( SELECT BusinessUnit.BusinessUnitId , Business ...

  9. CRM N:1 关系或者字段无法删除

    点开详细信息查看那些实体引用了该组件.查看内容如下: 1 查看窗体上有无该字段; 2 查看视图中有无该字段; 3 查看试图的 筛选条件; 4 查看试图的 查找列; 5 发布之后再试试.

  10. delphi HTML转义字符编码转换

    网上很多把HTML转换成纯文本格式的方法很多思路都是用正则表达式或者分析html代码替换的方法. 本文是利用IE完成转换,即利用IHTMLDocument2接口. Denon天Denon龙Denon ...