实现navstr的时候,我记得当时是为了帮下位机程序处理GPS文本信息。
navstr的主要功能就是根据一些分割标记,从字符串中提取出一些数据来。
navstr数据提取接口通常都需要传递一个界定符,工作原理是从【当前解析位置】到由函数指定的【下一个界定符】之间的字符串分割出来,然后根据需要转换为目标类型。
navstr.h
#pragma once
/*
** 解析状态
*/
#define NS_NOPOS -1 /* 未找到界定符 */
#define NS_OUTOFMEM -2 /* 输入缓冲区不足以存储目标 */
#define NS_FATAL -3 /* 发生不可恢复错误 */
#define NS_OK 1 /* 解析正确 */
/*
** 库特有的界定符
*/
#define NS_DELIMIT 0 /* 标示取到字符串结尾的界定符 */
/*
** 结构体navstr
*/
typedef struct _navparser
{
const char *text;
const char *pos;
const char *tail;
} navstr;
/*
** 解析为用户指定枚举量的回调函数原型
*/
typedef int (*ns_pfn_enum)(const char *str);
/*
** 初始化
*/
void ns_init(navstr *ns, const char *text);
/*
** 重置以从头解析
*/
void ns_reset(navstr *ns);
/*
** 字符串是否以特定文本开头
** 匹配时返回NS_OK,否则返回NS_NPOS
*/
int ns_start_with(navstr *ns, const char *head, int move);
/*
** 跳转到下一个指定的界定符之后
** 成功跳转后返回NS_OK,否则返回NS_NPOS
*/
int ns_goto_next(navstr *ns, const char *delimit);
/*
** 由界定符之前的文本,解析出一个整数
*/
int ns_int(navstr *ns, const char *delimit);
/*
** 由界定符之前的文本,解析出一个浮点数
*/
double ns_double(navstr *ns, const char *delimit);
/*
** 由界定符之前的文本,解析出一个字符串
*/
int ns_str(navstr *ns, const char *delimit, char *result, int rlen, int filter);
/*
** 由界定符之前的文本,解析出一个枚举量
*/
int ns_enum(navstr *ns, const char *delimit, ns_pfn_enum pfn);
/*
** 是否到达尾部
*/
int ns_end(const navstr *ns);
navstr.c
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include "navstr.h"
void ns_init(navstr *ns, const char *text)
{
ns->text = text;
ns->pos = text;
ns->tail = text + strlen(text);
}
void ns_reset(navstr *ns)
{
ns->pos = ns->text;
}
int ns_start_with(navstr *ns, const char *head, int move)
{
const char *p = strstr(ns->text, head);
int ret = (p && p == ns->text) ? NS_OK : NS_NOPOS;
if (ret == NS_OK && move)
ns->pos += strlen(head);
return ret;
}
int ns_goto_next(navstr *ns, const char *delimit)
{
if (ns->pos && ns->pos != ns->tail)
{
const char *p = strstr(ns->pos, delimit);
if (p)
{
p += strlen(delimit);
ns->pos = p;
return NS_OK;
}
}
return NS_NOPOS;
}
static int ns_data(navstr *ns, const char *delimit, char *result, int rlen)
{
if (ns->pos && ns->pos != ns->tail)
{
const char *p = NULL;
if (delimit != NS_DELIMIT)
p = strstr(ns->pos, delimit);
else
p = ns->tail;
if (p)
{
int len = (int)(p - ns->pos);
if (len >= rlen)
return NS_OUTOFMEM;
for (int i = 0; i < len; i++)
*result++ = *ns->pos++;
*result = 0;
if (delimit != NS_DELIMIT)
ns->pos = p + strlen(delimit);
else
ns->pos = ns->tail;
return NS_OK;
}
}
return NS_NOPOS;
}
int ns_int(navstr *ns, const char *delimit)
{
char buf[32];
int res = ns_data(ns, delimit, buf, 32);
if (res == NS_OK)
return atoi(buf);
assert(0);
return NS_FATAL;
}
double ns_double(navstr *ns, const char *delimit)
{
char buf[32];
int res = ns_data(ns, delimit, buf, 32);
if (res == NS_OK)
return atof(buf);
assert(0);
return NS_FATAL;
}
int ns_str(navstr *ns, const char *delimit, char *str, int slen, int filter)
{
int res = ns_data(ns, delimit, str, slen);
if (res == NS_OK && filter)
{
char *end = str + strlen(str) - 1;
while (str < end)
*str++ = *(str + 1);
*(str - 1) = 0;
}
return res;
}
int ns_enum(navstr *ns, const char *delimit, ns_pfn_enum pfn)
{
assert(pfn != 0x0);
char buf[128];
int res = ns_data(ns, delimit, buf, 128);
if (res == NS_OK)
return pfn(buf);
assert(0);
return NS_FATAL;
}
int ns_end(const navstr * ns)
{
return (ns->pos >= ns->tail) ? NS_OK : NS_NOPOS;
}
测试程序 main.c
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "navstr.h"
enum COMPUTE
{
SOL_ERROR,
SOL_PROCESSING,
SOL_COMPUTED,
};
enum NARROW
{
NARROW_INT,
NARROW_FLOAT
};
int get_compute_val(const char *str)
{
if (strcmp(str, "SOL_COMPUTED") == 0) return SOL_COMPUTED;
else if (strcmp(str, "SOL_PROCESSING") == 0) return SOL_PROCESSING;
else if (strcmp(str, "SOL_ERROR") == 0) return SOL_ERROR;
assert(0);
}
int get_narrow(const char *str)
{
if (strcmp(str, "NARROW_INT") == 0) return NARROW_INT;
else if (strcmp(str, "NARROW_FLOAT") == 0) return NARROW_FLOAT;
assert(0);
}
int main()
{
const char *instr = "#HEADINGA,COM3,0,60.0,FINESTEERING,2201,369102.000,00000000,0000,1114;"
"SOL_COMPUTED,,,NARROW_INT,,,1.622372866,90.625221252,-0.488150597,0.000000000,0.262617588,0.466465503,\"0004\",27,24,27,27,0,0,4,91*94714bcd";
navstr ns;
ns_init(&ns, instr);
{
int r;
r = ns_start_with(&ns, "#HEADINGA", 0);
r = ns_start_with(&ns, "#HEADINGB", 0);
ns_goto_next(&ns, ";");
int v;
v = ns_enum(&ns, ",,,", get_compute_val);
v = ns_enum(&ns, ",,,", get_narrow);
double f;
f = ns_double(&ns, ",");
f = ns_double(&ns, ",");
f = ns_double(&ns, ",");
for (int i = 0; i < 3; i++)
ns_goto_next(&ns, ",");
char str[32];
ns_str(&ns, ",", str, 32, 1);
v = ns_int(&ns, ",");
v = ns_int(&ns, ",");
}
{
int r = NS_OK;
char str[32];
ns_reset(&ns);
while (r != NS_NOPOS)
{
r = ns_str(&ns, ",", str, 32, 0);
if (r != NS_NOPOS)
printf("%s\n", str);
}
if (ns_end(&ns) != NS_OK)
{
ns_str(&ns, NS_DELIMIT, str, 32, 0);
printf("%s\n", str);
}
}
{
const char *instr = "$GPGGA,080632.00,0000.0000000,N,00000,0000000,E,0,00,0.0,-6378154.1620,M,17.162,M,,*73";
navstr ns;
ns_init(&ns, instr);
char str[32];
ns_start_with(&ns, "$GPGGA", 1);
ns_goto_next(&ns, ",");
for (int i = 0; i < 2; i++)
{
printf("%.2f\n", ns_double(&ns, ","));
printf("%.7f\n", ns_double(&ns, ","));
ns_str(&ns, ",", str, 32, 0);
printf("%s\n", str);
}
}
}

2128

被折叠的 条评论
为什么被折叠?



