嵌入式基础–解析字符串之模式匹配
接上一篇文章嵌入式基础–解析字符串(1),笔者给大家介绍一个更加简单的解析工具,那就是sscanf。
热身
大家在上C语言课,做C语言课程设计或实验时,应该经常接触printf和scanf,前者打印字符中到标准输出,而后者从标准输入读取并解析字符串。
sscanf和scanf类似,只不过它并不从标准输入读取,而是直接解析用户传入的字符串。
1 | int sscanf(const char *str, const char *format, ...); |
- str 待解析的字符串
- format 格式化参数
- … 变长参数,为一系列用于存放解析结果的变量的地址
- 返回成功解析的字段数量
格式化参数是啥意思?我们先来热身下。
1 | static void test(void) |
"Today is %d.%d.%d"为格式化参数,里面有普通字符,如Today is,和格式说明符,%d表int类型。sscanf依据格式化参数来解析str。对于普通字符,sscanf检查str是否与其一致。对于格式说明符,则按其含义来提取str中的内容,并将结果存入地址参数中。上述代码演示了提取年月日信息的方法,结果如下:
1 | ret=3, year:2021, month:7, day:31 |
如果还是对格式化参数没有印象的话,同学,你肯定没认真上C语言课,要不翻书复习下呗。笔者今天不是想从零开始讲sscanf,而是介绍一个鲜为人知的用法。
问题
再看一个例子,解析域名和端口号。
1 | static void test2(void) |
%s用于解析字符串(域名),%d用于解析int(端口号)。结果如下:
1 | ret=1, addr:www.baidu.com:80, port:0 |
这并不是我们期望的结果,sscanf将域名和端口号都当字符串来解析了。这是因为%s对应的字符串,遇到空白字符(空格、换行)或者是’\0’才算结束。结束之后,sscanf才会去理会:%d。
上述情况属于:想让字符串结束却没结束,从而解析了过多的内容。有时还会遇到相反的情况,请看下一个例子:
1 | static void test3(void) |
本想解析出完整的how are you,而输出的结果只有how。
模式
使用%s来匹配字符串,会受到很大的限制。但这并不意味着sscanf不好用,其还有一种匹配字符串的方法,那就是模式匹配。
模式的格式为:%[pattern],其中的pattern用于定义一个字符集,待匹配的字符串由这个字符集组成。pattern可以是多个字符,也可以使用-定义一个范围,还可以使用^反向定义字符集。说着有点抽象,让我们看些具体的示例吧。
- %[abcd] 匹配由a,b,c和d组成的字符串。比如对于
abcdefg这个字符串,其会匹配abcd。 - %[^abcd] 当pattern由
^开头时,其匹配pattern字符集以外的字符。因此,对于gfedcba这个字符串,其会匹配gfe。 - %[0-9a-fA-F] 其组成的字符集为0123456789abcdefABCDEF,其实就是16进制数字字符。
当使用-定义范围时,需要注意,起始字符必须小于结束字符。%[z-a]匹配的就不是范围,而是z,-和a这3个字符。
如果你学过正则表达式的话,对上述模式应该很熟悉。只不过,sscanf提供的模式匹配的功能比正则表达式简单的多。笔者在知道sscanf的这种隐藏用法后,屡试不爽,用的最多的就是^。
现在大家知道如何解析域名和端口号了吗?
要不再思考一下?
好了,答案如下:
1 | static void test2_fix(void) |
是不是非常简单,既然域名是:之前的内容,那就定义为%[^:]。
解析GPS
现在可以用sscanf来解析GPS了,GPS样例如下:
1 | $GNRMC,122921.000,A,3204.862246,N,11845.911047,E,0.099,191.76,280521,,E,A*00 |
直接上代码:
1 | static void parse_gps(const char *gps) |
下图标出了格式化参数中各格式说明符对应的字段。
第二个说明符,%*[^,]用于匹配时间122921.000。与之前不同的是,这里多了一个*,这表示不用解析对应字段的内容,后面的地址参数中也没有相关变量。你看,&valid, &latitude, &longitude分别存放有效标志字符,纬度和纬度,并没有时间变量的地址。%*c同理。
测试时,用3个用例进行测试,以测试成功和失败的场景。
1 | void parse_string_example(void) |
结果如下:
文中完整的示例代码,参见笔者基于stm32f407创建的demo工程:
1 | 地址:git@gitee.com:wenbodong/mcu_demo.git |
- 本文作者: 龙兄嵌入式
- 本文链接: https://hexo.880755.xyz/1970/01/01/zblog/download/97.嵌入式基础–解析字符串之模式匹配/