【开源】libserial_parse_text:命令行解析的基础库
借助五一假期,写了一个命令行解析的基础库,一般可用于串口命令解析、TCP命令解析等等。
具有以下几种特点:
- 不涉及到具体硬件, 纯软件协议,与具体硬件分离。
- 支持不定长命令行,逐个字符解码,可以支持不定长的命令参数解析。
- 支持解析过程中,对字符进行大小写转换,便于支持命令行大小写不敏感。
- 内存空间占用可控,可使用静态内存,也可以使用动态内存,内存空间可控。
- 分割符可灵活定义,支持自定义分割符和忽略符号,面向对象设计,可多个实例应用。
源码仓库:
GitHub - lovemengx/libserial_parse_text: 适用于单片机实现串口命令行解析的基础库, 支持动静态内存方式适用于单片机实现串口命令行解析的基础库, 支持动静态内存方式. Contribute to lovemengx/libserial_parse_text development by creating an account on GitHub.
https://github.com/lovemengx/libserial_parse_textlibserial_parse_text: 适用于单片机实现串口命令行解析的基础库
https://gitee.com/lovemengx/libserial_parse_text一、接口说明
// 缓存大小包含了接口内部所使用的数据结构空间
typedef struct{
char *buf; // 缓存地址, 用于存储解析后的字符串
unsigned int total; // 缓存大小, 标明该内存空间的总长度
}libserial_parse_buf_t;
#define LIBSERIAL_PARSE_SHIFT_NORMAL 0 // 不转换
#define LIBSERIAL_PARSE_SHIFT_LOWER 1 // 转换为小写字母
#define LIBSERIAL_PARSE_SHIFT_UPPER 2 // 转换为大写字母
/*---------------------------------------------------------------------
* 函数: libserial_parse_create
* 功能: 使用接口内部申请指定可用大小的空间(包含内部数据结构所用空间)
* 参数: size: 申请可用缓冲区大小
* 返回: NULL: 申请内存空间失败 >0: 申请成功
*---------------------------------------------------------------------*/
libserial_parse_buf_t *libserial_parse_create(unsigned int size);
/*---------------------------------------------------------------------
* 函数: libserial_parse_release
* 功能: 释放接口内部申请的内存空间
* 参数: spbuf: 由 libserial_parse_create() 创建的内存空间
* 返回: 无返回值
*---------------------------------------------------------------------*/
void libserial_parse_release(libserial_parse_buf_t *spbuf);
/*---------------------------------------------------------------------
* 函数: libserial_parse_internal_size
* 功能: 返回内部数据结构占用字节数
* 参数: 无需参数
* 返回: 内部数据结构占用字节数(不同字长的处理器可能不一样)
*---------------------------------------------------------------------*/
unsigned int libserial_parse_internal_size();
/*---------------------------------------------------------------------
* 函数: libserial_parse_init
* 功能: 使用用户提供的或创建接口的缓冲区, 初始化内部数据结构
* 参数: spbuf: 缓冲区 size: 缓冲区大小
* 返回: 0: 不满足最小长度要求 >0: 可存储最长文本的长度
* 备注: 默认设置忽略字符为: '\0', 默认设置分隔字符为: '\n'
*---------------------------------------------------------------------*/
unsigned int libserial_parse_init(libserial_parse_buf_t *spbuf);
/*---------------------------------------------------------------------
* 函数: libserial_parse_reset_buf
* 功能: 重置解析器缓冲区
* 参数: spbuf: 缓冲区
* 返回: 无返回值
* 备注: 不影响 libserial_parse_set_divide()\libserial_parse_set_ignore()
*---------------------------------------------------------------------*/
void libserial_parse_reset_buf(libserial_parse_buf_t *spbuf);
/*---------------------------------------------------------------------
* 函数: libserial_parse_set_divide
* 功能: 设定分隔字符
* 参数: splbuf: 缓冲区 divide: 分隔字符
* 返回: 无返回值
*---------------------------------------------------------------------*/
void libserial_parse_set_divide(libserial_parse_buf_t *spbuf, char divide);
/*---------------------------------------------------------------------
* 函数: libserial_parse_set_ignore
* 功能: 设定忽略字符, 传入 '\0' 代表不忽略任何字符
* 参数: splbuf: 缓冲区 ignore: 忽略字符
* 返回: 无返回值
* 备注: 双引号内的字符不会受此限制
*---------------------------------------------------------------------*/
void libserial_parse_set_ignore(libserial_parse_buf_t *spbuf, char ignore);
/*---------------------------------------------------------------------
* 函数: libserial_parse_set_shift
* 功能: 设置大小写字母转换
* 参数: splbuf: 缓冲区 shift: 0:不做转换 1:转换为小写字母 2:转换为大写字母
* 返回: 无返回值
*---------------------------------------------------------------------*/
void libserial_parse_set_shift(libserial_parse_buf_t *spbuf, char shift);
/*---------------------------------------------------------------------
* 函数: libserial_parse_text
* 功能: 解析以指定符号分隔或跳过的文本
* 参数: splbuf: 缓冲区 indata: 输入数据
* 返回: 0: 正在解析 >0:解析完成, 返回文本长度(不包含 '\0')
* 备注: 没有设定分隔符则会一直返回0, 数据超出缓存长度会返回解析完成
*---------------------------------------------------------------------*/
unsigned int libserial_parse_text(libserial_parse_buf_t *spbuf, char indata);
/*---------------------------------------------------------------------
* 函数: libserial_parse_text_nl (nl -> new line)
* 功能: 解析以换行符为终止符的文本(支持 '\n' 和 '\r\n')
* 参数: splbuf: 缓冲区 indata: 输入数据
* 返回: 0: 正在解析 >0:解析完成, 返回文本长度(不包含 '\0')
* 备注: 不受 libserial_parse_set_divide()\libserial_parse_set_ignore() 影响
*---------------------------------------------------------------------*/
unsigned int libserial_parse_text_nl(libserial_parse_buf_t *spbuf, char indata);
/*---------------------------------------------------------------------
* 函数: libserial_parse_finish
* 功能: 获取当前仍在缓冲区的字符数据
* 参数: splbuf: 缓冲区
* 返回: 0: 没有数据 >0:剩余字符串长度(不包含 '\0')
*---------------------------------------------------------------------*/
unsigned int libserial_parse_text_finish(libserial_parse_buf_t *spbuf);
二、示例代码
#include <stdio.h>
#include "libserial_parse_text.h"
#define iprintf(format,...) printf("[inf]%s():%05d " format , __func__, __LINE__,##__VA_ARGS__)
/*---------------------------------------------------------------------
* 函数: dynamic_mem_newline_example
* 功能: 动态内存版本以行为分割符的示例代码
*---------------------------------------------------------------------*/
int dynamic_mem_newline_example(const char* string)
{
libserial_parse_buf_t* spbuf = NULL;
unsigned int len = 0x00, i = 0x00;
// 创建缓冲区
if ((spbuf = libserial_parse_create(512)) == NULL) {
printf("reate parse buf failed.\n");
return -1;
}
// 初始化缓冲区
if ((len = libserial_parse_init(spbuf)) == 0x00) {
printf("memory is too small.\n");
libserial_parse_release(spbuf);
return -1;
}
// 开始解析字符串
printf("total:%d len:%d\n", spbuf->total, len);
for (i = 0; i < strlen(string); i++) {
if ((len = libserial_parse_text_nl(spbuf, string[i])) > 0) {
printf("[parse] : %-2d->[%s]\n", len, spbuf->buf);
}
}
// 检查是否还有剩下的字符串
if ((len = libserial_parse_text_finish(spbuf)) > 0) {
printf("[finish]: %-2d->[%s]\n", len, spbuf->buf);
}
// 释放动态内存
libserial_parse_release(spbuf);
return 0;
}
/*---------------------------------------------------------------------
* 函数: static_mem_newline_example
* 功能: 静态内存版本以行为分割符的示例代码
*---------------------------------------------------------------------*/
int static_mem_newline_example(const char* string)
{
char buff[512] = { 0 };
libserial_parse_buf_t spbuf;
unsigned int len = 0x00, i = 0x00;
// 指定静态内存
spbuf.buf = buff;
spbuf.total = sizeof(buff);
// 初始化缓冲区
if ((len = libserial_parse_init(&spbuf)) == 0x00) {
printf("memory is too small.\n");
return -1;
}
// 开始解析字符串
printf("total:%d len:%d\n", spbuf.total, len);
for (i = 0; i < strlen(string); i++) {
if ((len = libserial_parse_text_nl(&spbuf, string[i])) > 0) {
printf("[parse] : %-2d->[%s]\n", len, spbuf.buf);
}
}
// 检查是否还有剩下的字符串
if ((len = libserial_parse_text_finish(&spbuf)) > 0) {
printf("[finish]: %-2d->[%s]\n", len, spbuf.buf);
}
return 0;
}
/*---------------------------------------------------------------------
* 函数: static_mem_divide_example
* 功能: 静态内存版本以自定义分割符的示例代码
*---------------------------------------------------------------------*/
int static_mem_divide_example(const char* string)
{
char buff[512] = { 0 };
libserial_parse_buf_t spbuf;
unsigned int len = 0x00, i = 0x00;
// 指定静态内存
spbuf.buf = buff;
spbuf.total = sizeof(buff);
// 初始化缓冲区
if ((len = libserial_parse_init(&spbuf)) == 0x00) {
printf("memory is too small.\n");
return -1;
}
// 命令格式假定: 命令名称 参数1, 参数2, 参数3
libserial_parse_set_divide(&spbuf, ' '); // 设置分隔字符为空格, 提取命令名称
libserial_parse_set_ignore(&spbuf, '\0'); // 设置忽略字符为字符串结束符, 即不忽略任何字符
// 开始解析字符串
printf("total:%d len:%d\n", spbuf.total, len);
for (i = 0; i < strlen(string); i++) {
if ((len = libserial_parse_text(&spbuf, string[i])) > 0) {
printf("[parse] : %-2d->[%s]\n", len, spbuf.buf);
libserial_parse_set_divide(&spbuf, ','); // 设置分隔字符为逗号, 提取参数
libserial_parse_set_ignore(&spbuf, ' '); // 设置忽略字符为空格, 忽略参数中的空格字符
}
}
// 检查是否还有剩下的字符串
if ((len = libserial_parse_text_finish(&spbuf)) > 0) {
printf("[finish]: %-2d->[%s]\n", len, spbuf.buf);
}
return 0;
}
// 解析命令
int serial_command_text(libserial_parse_buf_t* spbuf, const char* string)
{
unsigned int i = 0x00;
for (i = 0; i < strlen(string); i++) {
if (libserial_parse_text(spbuf, string[i])) {
return 1;
}
}
return !!libserial_parse_text_finish(spbuf);
}
// 解析命令参数
int serial_exec_command(libserial_parse_buf_t* spbuf, const char* command, const char* paramet)
{
unsigned int i = 0x00;
printf("[command]: [%s]\n", command);
for (i = 0; i < strlen(paramet); i++) {
if (libserial_parse_text(spbuf, paramet[i])) {
printf("[paramet]: [%s]\n", spbuf->buf);
}
}
if (libserial_parse_text_finish(spbuf)) {
printf("[paramet]: [%s]\n", spbuf->buf);
}
printf("\n");
// 执行命令代码......
return 0;
}
/*---------------------------------------------------------------------
* 函数: serial_command_parse_example
* 功能: 动态内存版本完整的命令行解析示例代码
*---------------------------------------------------------------------*/
int serial_command_parse_example(const char* string)
{
unsigned int i = 0x00, j = 0x00;
libserial_parse_buf_t* spbuf1 = libserial_parse_create(256);
libserial_parse_buf_t* spbuf2 = libserial_parse_create(64);
libserial_parse_buf_t* spbuf3 = libserial_parse_create(256);
// 初始化缓冲区
libserial_parse_init(spbuf1);
libserial_parse_init(spbuf2);
libserial_parse_init(spbuf3);
// 命令格式假定: 命令名称 参数1,参数2,参数3
libserial_parse_set_divide(spbuf2, ' '); // 设置解析命令的分隔字符为空格, 提取命令名称
libserial_parse_set_ignore(spbuf2, '\0'); // 设置解析命令的忽略字符为字符串结束符, 即不忽略任何字符
libserial_parse_set_divide(spbuf3, ','); // 设置解析参数的分隔字符为逗号, 提取参数
libserial_parse_set_ignore(spbuf3, ' '); // 设置解析参数的忽略字符为空格, 忽略参数中的空格字符
// 模拟串口收到的数据
for (i = 0; i < strlen(string); i++)
{
// 解析字符串
if (libserial_parse_text_nl(spbuf1, string[i]) == 0) {
continue;
}
// 解析命令
printf("[parse]: [%s]\n", spbuf1->buf);
if (serial_command_text(spbuf2, spbuf1->buf) == 0) {
continue;
}
// 解析参数并执行命令
serial_exec_command(spbuf3, spbuf2->buf, spbuf1->buf + strlen(spbuf2->buf));
}
// 释放缓冲区
libserial_parse_release(spbuf1);
libserial_parse_release(spbuf2);
libserial_parse_release(spbuf3);
return 0;
}
int main(void)
{
const char* string = "@ABCDEFGHIJKLAA@\n\nQQ:1007566569\r\nlovemengx@qq.com\n123456789#++++++.....";
const char* strcmd = "reg_w 0x01=0x20, 0x02= 0x15, 0x03=0x56";
const char* strcmds = "wifi \"my wifi\",12345678\nvideo udp,192.168.1.115,8000\nreg_w 0x01=0x20, 0x02= 0x15, 0x03=0x56\nreg_r 0x01,0x02,0x05,0x06\nreboot\n";
// 静态内存解析以行分隔的字符串示例
printf("------------------------------------\n");
printf("static memory newline example...\n");
printf("------------------------------------\n");
static_mem_newline_example(string);
// 动态内存解析以行分隔的字符串示例
printf("------------------------------------\n");
printf("dynamic memory newline example...\n");
printf("------------------------------------\n");
dynamic_mem_newline_example(string);
printf("------------------------------------\n");
// 动态内存解析以自定义分隔和忽略的字符串示例
printf("------------------------------------\n");
printf("dynamic memory divide example...\n");
printf("------------------------------------\n");
static_mem_divide_example(strcmd);
printf("------------------------------------\n");
// 解析命令、参数并执行命令的完整示例
printf("------------------------------------\n");
printf("command parse example...\n");
printf("------------------------------------\n");
serial_command_parse_example(strcmds);
printf("------------------------------------\n");
return 0;
}
三、执行结果

【开源】libserial_parse_text:命令行解析的基础库的更多相关文章
- 【C++】cmdline——轻量级的C++命令行解析库
1.说明 cmdline是一个轻量级的c++命令行参数解析工具,全部源码只有一个cmdline.h头文件. 2.代码 20171210_命令行进行解析.cpp // 20171210_命令行进行解析. ...
- Python命令行解析argparse常用语法使用简介
查看原文:http://www.sijitao.net/2000.html python中的命令行解析最简单最原始的方法是使用sys.argv来实现,更高级的可以使用argparse这个模块.argp ...
- Python 命令行解析工具 Argparse介绍
最近在研究pathon的命令行解析工具,argparse,它是Python标准库中推荐使用的编写命令行程序的工具. 以前老是做UI程序,今天试了下命令行程序,感觉相当好,不用再花大把时间去研究界面问题 ...
- python实现命令行解析的argparse的使用
参考https://docs.python.org/3.6/library/argparse.html argparse模块使编写用户友好的命令行界面变得很容易.程序定义了它需要什么参数,argpar ...
- 使用命令行解析php文件
使用命令行解析php文件,这样可以调用Log4PHP库中的一些demo,因为默认的输出使用命令行作为输出. 建一个bat文件: echo 以下是使用命令行解析php文件 C:\xampp\php\ph ...
- 『Argparse』命令行解析
一.基本用法 Python标准库推荐使用的命令行解析模块argparse 还有其他两个模块实现这一功能,getopt(等同于C语言中的getopt())和弃用的optparse.因为argparse是 ...
- 2019-9-2-C#命令行解析工具
title author date CreateTime categories C#命令行解析工具 lindexi 2019-09-02 12:57:37 +0800 2018-2-13 17:23: ...
- Go语言 命令行解析(一)
命令行启动服务的方式,在后端使用非常广泛,如果有写过C语言的同学相信不难理解这一点!在C语言中,我们可以根据argc和argv来获取和解析命令行的参数,从而通过不同的参数调取不同的方法,同时也可以用U ...
- python模块----optparse模块、argparse模块 (命令行解析模块)
简介 optparse module---自版本3.2以来已弃用:optparse模块已弃用,将不再进一步开发:将继续使用argparse模块进行开发.optparse使用一种更具声明性的命令行解析方 ...
- Noah的学习笔记之Python篇:命令行解析
Noah的学习笔记之Python篇: 1.装饰器 2.函数“可变长参数” 3.命令行解析 注:本文全原创,作者:Noah Zhang (http://www.cnblogs.com/noahzn/) ...
随机推荐
- 企业级自定义表单引擎解决方案(十六)--Excel导入导出
Excel对于后端管理系统来说,永远都是绕不开的话题,开发Excel导入导出功能往往都比较麻烦,因为涉及到Excel导入模板制作.Excel表格数据与系统数据库表字段映射.Excel导入数据验证.验证 ...
- 【单元测试】Junit 4(三)--Junit4断言
1.0 前言 断言(assertion)是一种在程序中的一阶逻辑(如:一个结果为真或假的逻辑判断式),目的为了表示与验证软件开发者预期的结果--当程序执行到断言的位置时,对应的断言应该为真.若断言 ...
- uniapp之uni-starter小程序多端研发框架搭建与项目实践
随着移动互联网的飞速发展,无数移动APP琳琅满目:在移动App的发展的基础上,衍生了小程序.轻应用技术,它随时可用,但又无需安装卸载.小程序是一种不需要下载安装即可使用的应用,它实现了应用" ...
- js高级基础部分
基于尚硅谷的尚硅谷JavaScript高级教程提供笔记撰写,加入一些个人理解 github源码 博客下载 数据类型的分类和判断 主要问题 分类 基本(值)类型 Number ----- 任意数值 -- ...
- 【笔记】CF1714F Build a Tree and That Is It 及相关
题目传送门 细节较多的构造题. 解决思路 题目中虽然说是无根树,但我们可以钦定这棵树的根为 1,方便构造,这是不影响结果的. 以下记给定的三段长度为 \(a,b,c\) . 先考虑无解的情况. 首先, ...
- [leetcode] 713. Subarray Product Less Than K
题目 Given an array of integers nums and an integer k, return the number of contiguous subarrays where ...
- 匿名方法、Lambda表达和自定义泛型委托以及Func、Action系统泛型委托
1.匿名方法的概念:一个方法没有具体的名称,而只有关键字delegate.方法参数.方法体.这种方法是匿名方法. 匿名方法的好处:将具体方法和委托直接关联在一起,如果我们基于委托只需要一个方法的时候, ...
- 国产图形化的msf——Viper初体验
目录 免责声明: Viper简介 安装 使用 免责声明: 本文章仅供学习和研究使用,严禁使用该文章内容对互联网其他应用进行非法操作,若将其用于非法目的,所造成的后果由您自行承担,产生的一切风险与本文作 ...
- 读 Clean Code,关于变量命名和可维护代码
原文见 http://mindprod.com/jgloss/unmain.html 如何写出不能维护的代码 如何程序命名 容易输入的名字.比如:Fred,asdf 单字母的变量名.比如:a,b,c, ...
- python(牛客)试题解析2 - 中等
导航 一.NC192 二叉树的后序遍历 二.NC117 合并二叉树 三.求长度最长的的连续子序列使他们的和等于sum 四.按顺序取出固定长度内容并合并两个数组为一个新数组 五.输出所有结果小于k的整数 ...