《 C 语言的一些“骚操作”及其深层理解》之长字符串的拆分技巧
扫描二维码
随时随地手机看文章
长字符串的拆分技巧
很多时候我们需要进行长字符串的拆分。在振南的研发经历中,使用到这种操作的最典型的应用场合有三个。
1.NMEA协议数据的解析
NMEA可能很多人不太了解,但是说到GPS肯定大家都很熟悉。当我们从GPS模块中读取定位信息的时候,数据就是遵循NMEA协议格式的。图2.2为一个标准的GPS数据帧。
图2.2 一个符合NMEA协议标准的GPS数据帧
整个数据帧采用ASCII编码,它以$GP作为开始,后面依次排列的是各项参数,参数之间使用,作为分隔。比如$GPRMC为推荐定位信息,我当时就是使用这一条数据来获取经纬度信息的(当时是Intel杯嵌入式邀请赛需要作一个手持GPS跟踪器)。这条数据中N后面是纬度,E后面是经度。我们要作的就是将它们从整个数据帧(一个长字符串)中提取出来。所以,这就涉及到了所谓的“长串拆分”。
2.Shell命令行的命令解析
在很多项目中,我都习惯于基于串口编写一个后台Shell系统,可以起到一个基本的调试作用。从而一定程度上减少修改代码和固件烧录的次数。比如,项目中如果涉及DAC电压经常的调整输出,我就会在后台中设计一个命令SetV n,以便随时灵活的操控DAC。随着项目功能的升级,后台命令也会变得开始复杂。比如SetArg a b c d e f g h....,用于同时设置程序中多个关键参数的值;再比如SetV channel n freq a,设置某通道第n个信号的输出幅值和频率。
这些命令通过PC上的串口助手或调试终端来发送,比如超级终端、SecureCRT或XShell等。程序中从串口接收到命令之后,将其放入内存的缓冲区中,其形式就是一个字符串。命令字以及后面的若干参数之间使用空格来分隔。程序要匹配命令字,并提取参数,以便执行相应的操作。所以,这也涉及到长串的拆分。
3.DTU模块的AT指令解析
AT指令其实和NMEA是一个道理,它们都是一种通信协议格式,只不过AT指令更多使用在网络通信模块中,比如SIM800、ESP8266、HC06蓝牙串口等。举个例子,我们想知道网络信号强度,就可以向模块发送”AT+CSQ\r\n”,模块会返回”+CSQ: 29,0\r\n”。CSQ:后面的29就是信号强度。它们都是ASCII编码的,也就是一个字符串。我们需要将29从其中提取出来。当然,AT指令也有比较复杂的,字符串会比较长,包含的参数也会比较多。所以,要想使用这些网络模块实现网络通信,就必须实现对AT指令的解析。
说了这么多,都是在说长串拆分很重要。根本问题是如何实现它?很多人可能都会想到使用那个分隔字符,比如空格、逗号。然后去一个个数要提取的参数前面有几个分隔字符,然后后将相应位置上的字符组成一个新的短字符串。如图2.3所示。
图2.3 通过分隔字符定位要提取的部分
这种方法固然可行,但是略显笨拙。其实对于这种有明显分隔符的长字符串,我们可以采用“打散”或“爆炸”的思想,具体过程是这样的:将长字符串中的所有分隔符全部替换为’\0’,即字符串结束符。此时,长字符串就被分解成了在内存中顺序存放的若干个短字符串。如果要取出第n个短字符串,可以用这个函数:
很多时候我们需要一次性访问长字符串中的多个短字符串,此时振南经常会这样来作:通过一个循环,将长字符串中的所有分隔符替换为’\0’,在此过程中将每一个短字符串首字符的位置记录到一个数组中,代码如下:
好,举个例子:我们要提取”abc 1000 50 off 2500”中的”abc”、”50”和”off”,可以使用上面的函数来实现。