├── .gitignore ├── LICENSE ├── README.md ├── common.h ├── crstrlib.c ├── crstrlib.h └── test_crstrlib.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 K@Auto601 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CRStrLib - CloudRiver C语言字符串数值解析库 2 | 3 | ## 1。综述 4 | >杭州云江科技(CloudRiver) 出品, 获取更多OpenMV相关教程,加QQ群 凡哥带你玩转OpenMV < 564048763 > 5 | 6 | 7 | 此工程用于C语言解析字符串中的数值。 8 | 功能包括帧头帧尾校验,寻找字符串中的数值并将其转换为整数或者浮点数, 字符串无需按照特定格式, 是一个比较通用的字符串解析库。 9 | 发送过程中无需将浮点数转换为整数,负值也可以正常解析。 10 | 11 | 没第三方库(包括标准库)的引用, 可以方便地加入到单片机的工程或者添加到Arduino的库函数中。 12 | 13 | 写此函数的初衷是为了方便云江科技的用户, 在C语言中将OpenMV串口发送的字符串数据解析出来,提供了若干个范例。 14 | 15 | 16 | 17 | 使用样例见单元测试文件`test_crstrlib.c` 18 | 19 | 20 | ## 2. Quick Start 21 | 我们首先自定义一串字符串,模拟单片机接受的数据。 22 | 其中`HEAD`,`TAIL`是任意指定的帧头帧尾的校验数据。 23 | 我们对帧头帧尾进行校验,看数据是否匹配,如果不匹配的话,说明传输过程中出现了错误, 丢弃此帧。 24 | 25 | 然后我们根据不同数据类型,使用不同函数, 依次读入数据。 26 | 27 | 如果你想读入一个整数, 调用`CRStrLib_findNextInt`来寻找下面的一个整数类型的数据。 28 | 29 | 如果想读入一个浮点数值,那就调用`CRStrLib_findNextFloat`函数。 30 | 31 | 32 | ```c 33 | char *data = "HEAD,12,3,62.31,TAIL"; // 模拟单片机的数据 34 | int dataLen = CRStrLib_strLen(data); // 获取字符串长度 35 | int dataIdx = 0; // 记录字符串读取的下标 36 | int x; // x的值 整数 37 | int y; // y的值 整数 38 | float value; // 传感器的模拟值, 小数. 39 | 40 | /* 校验帧头帧尾 */ 41 | if (CRStrLib_isValidData(data, "HEAD", "TAIL") == FALSE){ 42 | /* 数据丢失无效数据 */ 43 | printf("Invailid data\n"); 44 | return; 45 | } 46 | 47 | /* 根据不同数据类型,使用不同函数, 依次读入数据 */ 48 | CRStrLib_findNextInt(data, dataLen, &dataIdx, &x); 49 | CRStrLib_findNextInt(data, dataLen, &dataIdx, &y); 50 | CRStrLib_findNextFloat(data, dataLen, &dataIdx, &value); 51 | 52 | /* 展示演示效果 */ 53 | printf("data read success\n"); 54 | printf("x: %d, y:%d, value:%.3f", x, y, value); 55 | ``` 56 | 57 | **输出结果** 58 | ``` 59 | data read success 60 | x: 12, y:3, value:62.310 61 | ``` 62 | 63 | ## 3. 主要API讲解 64 | 65 | ### 3.1. 帧头校验 66 | 67 | ```c 68 | Boolean CRStrLib_startWith(char *str, char *head); 69 | ``` 70 | **参数** 71 | 72 | `@Param char *str` 要匹配的字符串。 73 | `@Param char *head` 帧头字符串 74 | 75 | **返回值** 76 | 77 | 整数类型 : Boolean 78 | * TRUE : 等同于整数类型 1 79 | * FALSE : 等同于整数类型 0 80 | 81 | **演示样例** 82 | 83 | ```c 84 | char *str = "HEADA....."; 85 | char *head = "HEADA"; 86 | int isLegal = CRStrLib_startWith(str, head); 87 | ``` 88 | ### 3.2. 帧尾校验 89 | 90 | ```c 91 | Boolean CRStrLib_endWith(char *str, char *tail); 92 | ``` 93 | **参数** 94 | 95 | `@Param char *str` 要匹配的字符串。 96 | `@Param char *tail` 帧尾字符串。 97 | 98 | **返回值** 99 | 100 | 整数类型 : Boolean 101 | * TRUE : 等同于整数类型 1 102 | * FALSE : 等同于整数类型 0 103 | 104 | **演示样例** 105 | 106 | ```c 107 | char *str = ".....TAILA"; 108 | char *tail = "TAILA"; 109 | int isLegal = CRStrLib_startWith(str, tail); 110 | ``` 111 | 112 | ### 3.3. 帧校验 113 | 114 | 帧校验其实是融合了帧头校验跟帧尾校验两个函数。 115 | 116 | ```c 117 | Boolean CRStrLib_isValidData(char *str, char *head, char *tail); 118 | ``` 119 | 120 | 121 | **参数** 122 | 123 | `@Param char *str` 要匹配的字符串。 124 | `@Param char *head` 帧头字符串。 125 | `@Param char *tail` 帧尾字符串。 126 | 127 | **返回值** 128 | 129 | 整数类型 : Boolean 130 | * TRUE : 等同于整数类型 1 131 | * FALSE : 等同于整数类型 0 132 | 133 | **演示样例** 134 | 135 | ```c 136 | char *data = "HEAD,12,3,62.31,TAIL"; // 模拟单片机的数据 137 | 138 | /* 校验帧头帧尾 */ 139 | if (CRStrLib_isValidData(data, "HEAD", "TAIL") == FALSE){ 140 | /* 数据丢失无效数据 */ 141 | printf("Invailid data\n"); 142 | return; 143 | } 144 | ``` 145 | 146 | ### 3.4. 读入一个整数 147 | 148 | 读出的数值,通过指针的方式, 赋值给result指向的空间。 149 | 150 | ```c 151 | Status CRStrLib_findNextInt(char *str, int strLen, int *strIdx, int *result); 152 | ``` 153 | 154 | **参数** 155 | 156 | `@Param char *str` 要匹配的字符串。 157 | `@Param int strLen` 字符串的长度。 158 | `@Param int *strIdx` 字符串游标,指针类型。 159 | `@Param int *result` 读出的结果, 整数类型 160 | 161 | **返回值** 162 | 163 | 返回值: 状态码(Status) 整数类型 164 | 165 | ```c 166 | #define STATUS_SUCCESS 0 167 | #define STATUS_FAIL -1 168 | #define STATUS_NOT_FOUND 404 169 | ``` 170 | 171 | **演示样例** 172 | ```c 173 | char *data = "dsaserxc122,xaDSAAhg-232,--adaf897"; 174 | int strLen = CRStrLib_strLen(data); 175 | int strIdx = 0; 176 | int nextInt; 177 | int status; 178 | 179 | printf("data length : %d\n", strLen); 180 | 181 | /* 获取所有的整数 */ 182 | while(CRStrLib_findNextInt(data, strLen, &strIdx, &nextInt)!=STATUS_NOT_FOUND){ 183 | printf("Next int is %d , strIdx : %d\n", nextInt, strIdx); 184 | } 185 | ``` 186 | 187 | **输出结果** 188 | 189 | ``` 190 | data length : 34 191 | Next int is 122 , strIdx : 11 192 | Next int is -232 , strIdx : 24 193 | Next int is 897 , strIdx : 34 194 | ``` 195 | ### 3.5. 读入一个浮点数 196 | 197 | ```c 198 | Status CRStrLib_findNextFloat(char *str, int strLen, int *strIdx, float *result); 199 | ``` 200 | 201 | **参数** 202 | 203 | `@Param char *str` 要匹配的字符串。 204 | `@Param int strLen` 字符串的长度。 205 | `@Param int *strIdx` 字符串游标,指针类型。 206 | `@Param float *result` 读出的结果, 浮点数类型 207 | 208 | **返回值类型** 209 | 返回值: 状态码(Status) 整数类型 210 | 211 | ```c 212 | #define STATUS_SUCCESS 0 213 | #define STATUS_FAIL -1 214 | #define STATUS_NOT_FOUND 404 215 | ``` 216 | 217 | **演示样例** 218 | ```python 219 | char *data = "dsaserxc122.21,xaDSAAhg-232.,--adaf897.123asdf asdfa888,asdf-0.423, 0.0"; 220 | int strLen = CRStrLib_strLen(data); 221 | int strIdx = 0; 222 | float nextFloat; 223 | int status; 224 | 225 | printf("data length : %d\n", strLen); 226 | 227 | /* 获取所有的整数 */ 228 | while(CRStrLib_findNextFloat(data, strLen, &strIdx, &nextFloat)!=STATUS_NOT_FOUND){ 229 | printf("Next flaot is %.3f , strIdx : %d\n", nextFloat, strIdx); 230 | } 231 | ``` 232 | 233 | **输出结果** 234 | 235 | ``` 236 | data length : 73 237 | Next flaot is 122.210 , strIdx : 14 238 | Next flaot is -232.000 , strIdx : 27 239 | Next flaot is 897.123 , strIdx : 42 240 | Next flaot is 888.000 , strIdx : 55 241 | Next flaot is -0.423 , strIdx : 66 242 | Next flaot is 0.000 , strIdx : 73 243 | ``` -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 此文件主要用于C语言解析csv格式/其他格式的字符串, 提取数值,帧头帧尾校验 3 | * 4 | * Copyright (c) 2017/2017 ShunkaiXing@杭州云江科技 5 | * This work is licensed under the MIT license, see the file LICENSE for details. 6 | * 7 | * 获取更多OpenMV相关教程,加QQ群 凡哥带你玩转OpenMV < 564048763 > 8 | **/ 9 | 10 | #ifndef __COMMON_H__ 11 | #define __COMMON_H__ 12 | 13 | /* status 状态码 */ 14 | typedef int Status; 15 | 16 | #define STATUS_SUCCESS 0 17 | #define STATUS_FAIL -1 18 | #define STATUS_NOT_FOUND 404 19 | 20 | /* boolean */ 21 | typedef int Boolean; 22 | #define FALSE 0 23 | #define TRUE 1 24 | 25 | 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /crstrlib.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 此文件主要用于C语言解析csv格式/其他格式的字符串, 提取数值,帧头帧尾校验 3 | * 4 | * Copyright (c) 2017/2017 ShunkaiXing@杭州云江科技 5 | * This work is licensed under the MIT license, see the file LICENSE for details. 6 | * 7 | * 获取更多OpenMV相关教程,加QQ群 凡哥带你玩转OpenMV < 564048763 > 8 | **/ 9 | 10 | 11 | #include "crstrlib.h" 12 | 13 | /* 判断是否为数值字符 '0' - '9'*/ 14 | Boolean CRStrLib_isNum(char c){ 15 | if (c >= '0' && c <= '9'){ 16 | return TRUE; 17 | } 18 | return FALSE; 19 | } 20 | 21 | /* 将字符转换为数值 '0' -> 0 */ 22 | int CRStrLib_char2Int(char c){ 23 | return (int)(c - '0'); 24 | } 25 | 26 | /* 判断是否为正负号 */ 27 | Boolean CRStrLib_isSymbol(char c){ 28 | if( c == '+' || c == '-'){ 29 | return TRUE; 30 | } 31 | return FALSE; 32 | } 33 | 34 | int CRStrLib_strLen(char *str){ 35 | int i; 36 | 37 | /* 为了防止内存溢出 限定string的长度 */ 38 | for(i = 0; i < MAX_STR_NUM; i++){ 39 | if(str[i] == '\0'){ 40 | return i; 41 | } 42 | } 43 | 44 | return MAX_STR_NUM; 45 | 46 | } 47 | /** 48 | * 寻找下一个整数 49 | **/ 50 | Status CRStrLib_findNextInt(char *str, int strLen, int *strIdx, int *result){ 51 | int symbol = 1; // 数值正负 52 | int baseValue = 0; 53 | 54 | /* 寻找首部为数值的子字符 */ 55 | while(CRStrLib_isNum(str[*strIdx]) == FALSE){ 56 | (*strIdx) += 1; 57 | if (*strIdx >= strLen){ 58 | /* 如果没有整数 */ 59 | return STATUS_NOT_FOUND; 60 | } 61 | } 62 | /* 考虑符号 */ 63 | if(*strIdx > 0 && CRStrLib_isSymbol(str[*strIdx - 1]) == TRUE){ 64 | if (str[*strIdx - 1] == '-'){ 65 | symbol = -1; 66 | } 67 | } 68 | 69 | /* 寻找相连的所有数字字符 */ 70 | while(*strIdx < strLen && CRStrLib_isNum(str[*strIdx])){ 71 | baseValue *= 10; 72 | // printf("add num : %c %d\n", str[*strIdx], (int)str[*strIdx]); 73 | baseValue += CRStrLib_char2Int(str[*strIdx]); 74 | *strIdx += 1; 75 | } 76 | 77 | *result = symbol * baseValue; 78 | 79 | return STATUS_SUCCESS; 80 | } 81 | 82 | /* 寻找下一个浮点数 */ 83 | Status CRStrLib_findNextFloat(char *str, int strLen, int *strIdx, float *result){ 84 | 85 | int intPart = 0; // 整数部分 86 | float decimalPart = 0.0; // 小数部分 87 | int status; 88 | int symbol = 1; 89 | 90 | /* 寻找首部为数值的子字符 */ 91 | while(CRStrLib_isNum(str[*strIdx]) == FALSE){ 92 | (*strIdx) += 1; 93 | if (*strIdx >= strLen){ 94 | /* 如果没有整数 */ 95 | return STATUS_NOT_FOUND; 96 | } 97 | } 98 | 99 | /* 考虑符号 */ 100 | if(*strIdx > 0 && CRStrLib_isSymbol(str[*strIdx - 1]) == TRUE){ 101 | if (str[*strIdx - 1] == '-'){ 102 | symbol = -1; 103 | } 104 | } 105 | 106 | status = CRStrLib_findNextInt(str, strLen, strIdx, &intPart); 107 | if (status != STATUS_SUCCESS){ 108 | /* 整数部分获取失败 */ 109 | return status; 110 | } 111 | 112 | /* 只需要获取绝对值 */ 113 | if(intPart < 0){ 114 | intPart *= -1; 115 | } 116 | 117 | /* 查看下一位是不是小数点位 */ 118 | if (str[*strIdx] == '.' && CRStrLib_isNum(str[(*strIdx) + 1])){ 119 | // int pointIdx = strIdx; // 记录小数点的位置 120 | *strIdx += 1; 121 | float base = 0.1; 122 | 123 | // 需要考虑到小数部分0的情况 124 | // CRStrLib_findNextInt(str, strLen, strIdx, &decimalPart); 125 | while(*strIdx < strLen && CRStrLib_isNum(str[*strIdx]) == TRUE){ 126 | decimalPart += base * (float)CRStrLib_char2Int(str[*strIdx]); 127 | base *= 0.1; 128 | *strIdx += 1; 129 | } 130 | 131 | } 132 | 133 | // 添加正负号 134 | *result = symbol * ((float)intPart + decimalPart); 135 | 136 | return STATUS_SUCCESS; 137 | } 138 | 139 | /* 判断是否为有效数据 */ 140 | Boolean CRStrLib_isValidData(char *str, char *head, char *tail){ 141 | /* 校验帧头帧尾*/ 142 | if (CRStrLib_startWith(str, head) == TRUE && CRStrLib_endWith(str, tail) == TRUE){ 143 | return TRUE; 144 | } 145 | 146 | return FALSE; 147 | } 148 | 149 | /* 判断数据帧头是否匹配 */ 150 | Boolean CRStrLib_startWith(char *str, char *head){ 151 | int strLen = strlen(str); 152 | int headLen = strlen(head); 153 | int i; 154 | if (strLen < headLen){ 155 | return FALSE; 156 | } 157 | 158 | for(i = 0; i < headLen; i += 1){ 159 | if (str[i] != head[i]){ 160 | return FALSE; 161 | } 162 | } 163 | return TRUE; 164 | } 165 | 166 | /* 判断帧尾是否匹配 */ 167 | Boolean CRStrLib_endWith(char *str, char *tail){ 168 | int strLen = strlen(str); 169 | int tailLen = strlen(tail); 170 | int i; 171 | if (strLen < tailLen){ 172 | return FALSE; 173 | } 174 | 175 | for(i = 0; i < tailLen; i += 1){ 176 | if (str[strLen - i - 1] != tail[tailLen - i - 1]){ 177 | return FALSE; 178 | } 179 | } 180 | return TRUE; 181 | } 182 | -------------------------------------------------------------------------------- /crstrlib.h: -------------------------------------------------------------------------------- 1 | #ifndef CRSTRLIB_H_INCLUDED 2 | #define CRSTRLIB_H_INCLUDED 3 | 4 | #include "common.h" 5 | 6 | #define MAX_STR_NUM 1000 7 | 8 | 9 | Boolean isNum(char c); 10 | 11 | Boolean isSymbol(char c); 12 | 13 | int CRStrLib_char2Int(char c); 14 | 15 | int CRStrLib_strLen(char *str); 16 | 17 | Status CRStrLib_findNextInt(char *str, int strLen, int *strIdx, int *result); 18 | 19 | Status CRStrLib_findNextFloat(char *str, int strLen, int *strIdx, float *result); 20 | 21 | Boolean CRStrLib_isValidData(char *str, char *head, char *tail); 22 | 23 | Boolean CRStrLib_startWith(char *str, char *head); 24 | 25 | Boolean CRStrLib_endWith(char *str, char *tail); 26 | 27 | #endif // CRSTRLIB_H_INCLUDED 28 | -------------------------------------------------------------------------------- /test_crstrlib.c: -------------------------------------------------------------------------------- 1 | /* 2 | * 此文件为crstrlib的单元测试文件, 可以通过测试样例,了解crstrlib库的用法。 3 | * 4 | * Copyright (c) 2017/2017 ShunkaiXing@杭州云江科技 5 | * This work is licensed under the MIT license, see the file LICENSE for details. 6 | * 7 | * 获取更多OpenMV相关教程,加QQ群 凡哥带你玩转OpenMV < 564048763 > 8 | **/ 9 | 10 | #include "crstrlib.h" 11 | 12 | int main(){ 13 | // testFindNextInt(); 14 | // testFindNextFloat(); 15 | diyProtocal(); 16 | } 17 | 18 | /* csv通信协议模拟 x,y为整数,数值为浮点数 */ 19 | void diyProtocal(){ 20 | 21 | char *data = "HEAD,12,3,62.31,TAIL"; // 模拟单片机的数据 22 | int dataLen = CRStrLib_strLen(data); // 获取字符串长度 23 | int dataIdx = 0; // 记录字符串读取的下标 24 | int x; // x的值 整数 25 | int y; // y的值 整数 26 | float value; // 传感器的模拟值, 小数. 27 | 28 | /* 校验帧头帧尾 */ 29 | if (CRStrLib_isValidData(data, "HEAD", "TAIL") == FALSE){ 30 | /* 数据丢失无效数据 */ 31 | printf("Invailid data\n"); 32 | return; 33 | } 34 | 35 | /* 根据不同数据类型,使用不同函数, 依次读入数据 */ 36 | CRStrLib_findNextInt(data, dataLen, &dataIdx, &x); 37 | CRStrLib_findNextInt(data, dataLen, &dataIdx, &y); 38 | CRStrLib_findNextFloat(data, dataLen, &dataIdx, &value); 39 | 40 | printf("data read success\n"); 41 | printf("x: %d, y:%d, value:%.3f", x, y, value); 42 | 43 | } 44 | 45 | void testFindNextInt(){ 46 | char *data = "dsaserxc122,xaDSAAhg-232,--adaf897"; 47 | int strLen = CRStrLib_strLen(data); 48 | int strIdx = 0; 49 | int nextInt; 50 | int status; 51 | 52 | printf("data length : %d\n", strLen); 53 | 54 | /* 获取所有的整数 */ 55 | while(CRStrLib_findNextInt(data, strLen, &strIdx, &nextInt)!=STATUS_NOT_FOUND){ 56 | printf("Next int is %d , strIdx : %d\n", nextInt, strIdx); 57 | } 58 | } 59 | /* 测试寻找下一个浮点数 */ 60 | void testFindNextFloat(){ 61 | char *data = "dsaserxc122.21,xaDSAAhg-232.,--adaf897.123asdf asdfa888,asdf-0.423, 0.0"; 62 | int strLen = CRStrLib_strLen(data); 63 | int strIdx = 0; 64 | float nextFloat; 65 | int status; 66 | 67 | printf("data length : %d\n", strLen); 68 | 69 | /* 获取所有的整数 */ 70 | while(CRStrLib_findNextFloat(data, strLen, &strIdx, &nextFloat)!=STATUS_NOT_FOUND){ 71 | printf("Next flaot is %.3f , strIdx : %d\n", nextFloat, strIdx); 72 | } 73 | 74 | } 75 | --------------------------------------------------------------------------------