文档章节

ACL_VSTRING --字符串操作的法宝

郑树新
 郑树新
发布于 2014/09/03 12:11
字数 2367
阅读 37
收藏 0

一、概述

  当我们在使用C++、JAVA、.NET等面向对象语言甚至象PHP等脚本程序编写字符串处理程序,觉得字符串处理是如此的简单,但当用C编写字符串处理程序时,用得最多可能是诸如:snprintf 、strchr、strcat等标准C函数,但若遇到字符串缓冲区需要动态变化时,就不得不多做一些工作来做内存重新分配的事情,嗯,好繁琐的工作。而POSTFIX代码里有一个非常好用的字符串处理函数库:基于VSTRING结构的字符串处理函数集合,ACL作者将该函数集移植至ACL工程中(重新命名为ACL_VSTRING,没办法,C语言没有象C++那样的命名空间)并使该库可以运行在多个平台上(UNIX、WIN32等),同时增加了一些常用的功能。本文就介绍一下ACL_VSTRING函数库的使用。

 

二、常用函数接口

1、创建与释放

/**
 * 动态分配一个 ACL_VSTRING 对象并指定内部缓冲区的初始化大小
 * @param len {size_t} 初始时缓冲区大小
 * @return {ACL_VSTRING*} 新分配的 ACL_VSTRING 对象
 */
ACL_API ACL_VSTRING *acl_vstring_alloc(size_t len);

/**
 * 释放由 acl_vstring_alloc 动态分配的 ACL_VSTRING 对象
 * @param vp {ACL_VSTRING*}
 * @return {ACL_VSTRING*} 永远为 NULL,所以不必关心返回值
 */
ACL_API ACL_VSTRING *acl_vstring_free(ACL_VSTRING *vp);

 2、字符串拷贝及添加

/**
 * 拷贝字符串
 * @param vp {ACL_VSTRING*}
 * @param src {const char*} 源字符串
 * @return {ACL_VSTRING*} 与 vp 相同
 */
ACL_API ACL_VSTRING *acl_vstring_strcpy(ACL_VSTRING *vp, const char *src);

/**
 * 附加拷贝字符串
 * @param vp {ACL_VSTRING*}
 * @param src {const char*} 源字符串
 * @return {ACL_VSTRING*} 与 vp 相同
 */
ACL_API ACL_VSTRING *acl_vstring_strcat(ACL_VSTRING *vp, const char *src);

/**
 * 向缓冲区按格式方式添加数据
 * @param vp {ACL_VSTRING*}
 * @param format {const char*} 格式化字符串
 * @param ... 变参序列
 * @return {ACL_VSTRING*} 与 vp 相同
 */
ACL_API ACL_VSTRING *acl_vstring_sprintf(ACL_VSTRING *vp, const char *format,...);

/**
 * 以附加方式向缓冲区按格式方式添加数据
 * @param vp {ACL_VSTRING*}
 * @param format {const char*} 格式化字符串
 * @param ... 变参序列
 * @return {ACL_VSTRING*} 与 vp 相同
 */
ACL_API ACL_VSTRING *acl_vstring_sprintf_append(ACL_VSTRING *vp, const char *format,...);

/**
 * 按规定格式添加数据
 * @param vp {ACL_VSTRING*}
 * @param format {const char*}
 * @param ap {va_list}
 * @return {ACL_VSTRING*} 与 vp 相同
 * @see acl_vstring_sprintf
 */
ACL_API ACL_VSTRING *acl_vstring_vsprintf(ACL_VSTRING *vp, const char *format, va_list ap);

/**
 * 按规定格式向尾部添加数据
 * @param vp {ACL_VSTRING*}
 * @param format {const char*}
 * @param ap {va_list}
 * @return {ACL_VSTRING*} 与 vp 相同
 */
ACL_API ACL_VSTRING *acl_vstring_vsprintf_append(ACL_VSTRING *vp, const char *format, va_list ap);

  其中,acl_vstring_strcpy 功能与 strcpy 相似,但 acl_vstring_strcpy 不会产生内存溢出问题,因为ACL_VSTRING内存是自动调整的;acl_vstring_strcat 与 strcat 功能相似,但效率却要比 strcat 高,因为 strcat 需要先从字符串头移到字符串尾后才开始添加,并且还可能产生内存越界问题,而 acl_vstring_strcat 内部直接在 ACL_VSTRING 的字符串尾部添加(得益于ACL_VSTRING的内部结构的指针成员),所以效率更高,同时也不存在内存非法越界的问题;acl_vstring_sprintf 与 snprintf 功能类似;acl_vstring_sprintf_append 是对 acl_vstring_sprintf 函数功能的一种扩充;acl_vstring_vsprintf 与 vsnprintf 类似,acl_vstring_vsprintf_append 是对 acl_vstring_vsprintf 的功能扩展。

  除了以上专门针对字符串的一些拷贝、添加功能外,ACL_VSTRING还支持非字符串数据的拷贝、添加,接口如下:

/**
 * 拷贝内存区
 * @param vp {ACL_VSTRING*}
 * @param src {const char*} 源数据地址
 * @param len {size_t} 源数据长度
 * @return {ACL_VSTRING*} 与 vp 相同
 */
ACL_API ACL_VSTRING *acl_vstring_memcpy(ACL_VSTRING *vp, const char *src, size_t len);

/**
 * 拷贝内存区
 * @param vp {ACL_VSTRING*}
 * @param src {const char*} 源数据地址
 * @param len {size_t} 源数据长度
 * @return {ACL_VSTRING*} 与 vp 相同
 */
ACL_API ACL_VSTRING *acl_vstring_memcat(ACL_VSTRING *vp, const char *src, size_t len);
 

 3、字符串查找

/**
 * 查找某个字符
 * @param vp {ACL_VSTRING*}
 * @param ch {int} 要查找的字符
 * @return {char*} 目标字符所在位置的地址, 如果未查到则返回 NULL, 注:该返回地址是不能
 *  被单独释放的,因为其由 ACL_VSTRING 对象统一进行管理
 */
ACL_API char *acl_vstring_memchr(ACL_VSTRING *vp, int ch);

/**
 * 查找某个字符串,字符串大小写敏感
 * @param vp {ACL_VSTRING*}
 * @param needle {const char*} 要查找的字符
 * @return {char*} 目标字符所在位置的地址, 如果未查到则返回 NULL, 注:该返回地址是不能
 *  被单独释放的,因为其由 ACL_VSTRING 对象统一进行管理
 */
ACL_API char *acl_vstring_strstr(ACL_VSTRING *vp, const char *needle);

/**
 * 查找某个字符串,忽略字符串大小写
 * @param vp {ACL_VSTRING*}
 * @param needle {const char*} 要查找的字符
 * @return {char*} 目标字符所在位置的地址, 如果未查到则返回 NULL, 注:该返回地址是不能
 *  被单独释放的,因为其由 ACL_VSTRING 对象统一进行管理
 */
ACL_API char *acl_vstring_strcasestr(ACL_VSTRING *vp, const char *needle);

/**
 * 从后向前查找字符串,字符串大小写敏感
 * @param vp {ACL_VSTRING*}
 * @param needle {const char*} 要查找的字符
 * @return {char*} 目标字符所在位置的地址, 如果未查到则返回 NULL, 注:该返回地址是不能
 *  被单独释放的,因为其由 ACL_VSTRING 对象统一进行管理
 */
ACL_API char *acl_vstring_rstrstr(ACL_VSTRING *vp, const char *needle);

/**
 * 从后向前查找字符串,字符串大小写不敏感
 * @param vp {ACL_VSTRING*}
 * @param needle {const char*} 要查找的字符
 * @return {char*} 目标字符所在位置的地址, 如果未查到则返回 NULL, 注:该返回地址是不能
 *  被单独释放的,因为其由 ACL_VSTRING 对象统一进行管理
 */
ACL_API char *acl_vstring_rstrcasestr(ACL_VSTRING *vp, const char *needle);

   这些字符串查找函数要比标准C的查找函数功能更为强大。

  此外,ACL_VSTRING还提供了一些方便使用的宏,如下:

4、常用宏

/**
 * 取得当前 ACL_VSTRING 数据存储地址
 * @param vp {ACL_VSTRING*}
 * @return {char*}
 */
#define acl_vstring_str(vp)		((char *) (vp)->vbuf.data)

/**
 * 取得当前 ACL_VSTRING 的数据偏移指针位置
 * @param vp {ACL_VSTRING*}
 * @return {char*}
 */
#define acl_vstring_end(vp)		((char *) (vp)->vbuf.ptr)

/**
 * 取得当前 ACL_VSTRING 所存储的数据的长度
 * @param vp {ACL_VSTRING*}
 * @return {int}
 */
#define ACL_VSTRING_LEN(vp)		(size_t) ((vp)->vbuf.ptr - (vp)->vbuf.data)

/**
 * 将 ACL_VSTRING 的数据偏移指针位置置 0
 * @param vp {ACL_VSTRING*}
 */
#define ACL_VSTRING_TERMINATE(vp)	{ if ((vp)->vbuf.cnt <= 0) \
					ACL_VSTRING_SPACE((vp),1); \
				 	 *(vp)->vbuf.ptr = 0; }

/**
 * 重置 ACL_VSTRING 内部缓冲区
 * @param vp {ACL_VSTRING*}
 */
#define ACL_VSTRING_RESET(vp)		{ (vp)->vbuf.ptr = (vp)->vbuf.data; \
					  (vp)->vbuf.cnt = (vp)->vbuf.len; }

/**
 * 添加一个字符至 ACL_VSTRING 缓冲区
 * @param vp {ACL_VSTRING*}
 * @param ch {int} 字符
 */
#define	ACL_VSTRING_ADDCH(vp, ch)	ACL_VBUF_PUT(&(vp)->vbuf, ch)

   当然,除了以上常用函数及宏外,还有一些其它的函数及宏,请参考 lib_acl/include/stdlib/acl_vstring.h。

三、举例

#include "lib_acl.h"

static void end(void)
{
#ifdef ACL_MS_WINDOWS
	getchar();
#endif
}

#define	STR	acl_vstring_str

// 字符串查找,大小写敏感

static void string_find(ACL_VSTRING *vp, const char *needle)
{
	char *ptr;

	ptr = acl_vstring_strstr(vp, needle);
	if (ptr)
		printf(">>>acl_vstring_strstr: find %s from %s, ptr: %s\r\n", needle, STR(vp), ptr);
	else
		printf(">>>acl_vstring_strstr: not find %s from %s\r\n", needle, STR(vp));
}

// 字符串查找,大小写不敏感

static void string_case_find(ACL_VSTRING *vp, const char *needle)
{
	char *ptr;

	ptr = acl_vstring_strcasestr(vp, needle);
	if (ptr)
		printf(">>>acl_vstring_strcasestr: find %s from %s, ptr: %s\r\n", needle, STR(vp), ptr);
	else
		printf(">>>acl_vstring_strcasestr: not find %s from %s\r\n", needle, STR(vp));
}

// 从尾部向前查找字符串,大小写敏感

static void string_rfind(ACL_VSTRING *vp, const char *needle)
{
	char *ptr;

	ptr = acl_vstring_rstrstr(vp, needle);
	if (ptr)
		printf(">>>acl_vstring_rstrstr: find %s from %s, ptr: %s\r\n", needle, STR(vp), ptr);
	else
		printf(">>>acl_vstring_rstrstr: not find %s from %s\r\n", needle, STR(vp));
}

// 从尾部向前查找字符串,大小写不敏感

static void string_case_rfind(ACL_VSTRING *vp, const char *needle)
{
	char *ptr;

	ptr = acl_vstring_rstrcasestr(vp, needle);
	if (ptr)
		printf(">>>acl_vstring_rstrcasestr: find %s from %s, ptr: %s\r\n", needle, STR(vp), ptr);
	else
		printf(">>>acl_vstring_rstrcasestr: not find %s from %s\r\n", needle, STR(vp));
}

// 需要查找的字符串表

static char *needle_tab[] = {
	"h",
	"el",
	"o",
	"e",
	"l",
	"lo",
	"he",
	"He",
	"hello",
	"hel",
	"Hel",
	"helo",
	NULL
};

int main(int argc acl_unused, char *argv[] acl_unused)
{
	ACL_VSTRING *vp = acl_vstring_alloc(256);  // 分配 ACL_VSTRING对象
	char *ptr;
	int   i;

	// 字符串拷贝
	acl_vstring_strcpy(vp, "大家好,中国人民,Hi大家好, Hello World! 中国人民银行!");

	printf(">>>%s\r\n", acl_vstring_str(vp));
	ptr = acl_vstring_strstr(vp, "Hello");  // 查询字符串,区分大小写
	if (ptr)
		printf(">>ok, find it, ptr = %s\r\n", ptr);
	else
		printf(">>error, no find it\r\n");

	ptr = acl_vstring_strcasestr(vp, "WORLD");  // 查询字符串,不区分大小写
	if (ptr)
		printf(">>ok, find it, ptr = %s\r\n", ptr);
	else
		printf(">>error, no find it\r\n");

	ptr = acl_vstring_strstr(vp, "中国");
	if (ptr)
		printf(">>ok, find it, ptr = %s\r\n", ptr);
	else
		printf(">>error, no find it\r\n");

	ptr = acl_vstring_strcasestr(vp, "Hi大家好");
	if (ptr)
		printf(">>ok, find it, ptr = %s\r\n", ptr);
	else
		printf(">>error, no find it\r\n");

	ptr = acl_vstring_memchr(vp, 'W');  // 查询某个字符
	if (ptr)
		printf(">>ok, find it, ptr = %s\r\n", ptr);
	else
		printf(">>error, no find it\r\n");

	acl_vstring_strcpy(vp, "hello");  // 字符串拷贝
	ptr = acl_vstring_strstr(vp, "h");  // 字符串查找
	if (ptr)
		printf(">>>find it, ptr: %s\r\n", ptr);
	else
		printf(">>>not find it\r\n");

	printf("\r\n------------------------------------------------------------\r\n");
	for (i = 0; needle_tab[i]; i++) {
		string_rfind(vp, needle_tab[i]);
	}

	printf("\r\n------------------------------------------------------------\r\n");
	for (i = 0; needle_tab[i]; i++) {
		string_case_rfind(vp, needle_tab[i]);
	}

	printf("\r\n------------------------------------------------------------\r\n");
	for (i = 0; needle_tab[i]; i++) {
		string_find(vp, needle_tab[i]);
	}

	printf("\r\n------------------------------------------------------------\r\n");
	for (i = 0; needle_tab[i]; i++) {
		string_case_find(vp, needle_tab[i]);
	}

	printf("\r\n------------------------------------------------------------\r\n");
	const char *s1 = "hello world", *s2 = "WOrld", *s3 = "world";

	printf("strrncasecmp: %s %s %s, n: %d\n", s1,
		strrncasecmp(s1, s2, strlen(s2)) == 0 ? "==" : "!=", s2, (int) strlen(s2));
	printf("strrncasecmp: %s %s %s, n: %d\n", s1,
		strrncasecmp(s1, s2, strlen(s2) + 1) == 0 ? "==" : "!=", s2, (int) strlen(s2) + 1);

	s1 = "www.hexun.com";
	s2 = ".hexun.com";
	printf("strrncasecmp: %s %s %s, n: %d\n", s1,
		strrncasecmp(s1, s2, strlen(s2)) == 0 ? "==" : "!=", s2, (int) strlen(s2));

	printf("\r\n------------------------------------------------------------\r\n");
	printf("strrncmp: %s %s %s, n: %d\n", s1, strrncmp(s1, s2, strlen(s2)) == 0 ? "==" : "!=", s2, (int) strlen(s2));
	printf("strrncmp: %s %s %s, n: 3\n", s1, strrncmp(s1, s2, 3) == 0 ? "==" : "!=", s2);
	printf("strrncmp: %s %s %s, n: %d\n", s1, strrncmp(s1, s3, strlen(s3)) == 0 ? "==" : "!=", s3, (int) strlen(s3));
	printf("strrncmp: %s %s %s, n: %d\n", s1, strrncmp(s1, s3, strlen(s3) + 1) == 0 ? "==" : "!=",
		s3, (int) strlen(s3) + 1);

	// 带格式写字符串
	acl_vstring_sprintf(vp, "max long long int: %llu", (unsigned long long int) -1);
	printf("%s\n", acl_vstring_str(vp));

	// 释放 ACL_VSTRING对象
	
	acl_vstring_free(vp);

	end();
	return (0);
}

 

四、小结

  ACL_VSTRING强大易用的功能足可以使你编写常见的字符串应用例子,使你省去了诸如内存重新分配等琐事,一方面提高了开发效率,另一方面减少了出错概率。

  ACL库下载地址: http://acl.sourceforge.net

 

      个人微博:http://weibo.com/zsxxsz

© 著作权归作者所有

郑树新

郑树新

粉丝 104
博文 87
码字总数 161171
作品 2
昌平
程序员
私信 提问
acl 3.0.8 版本发布!

此次 acl (https://sourceforge.net/projects/acl/) 新版本的发布,主要是修复了一些存在的 BUG,同时伴随一些模块的性能提升,以及针对 master 服务器框架的功能扩展,内容如下: acl 3.0....

郑树新
2013/06/23
1K
2
acl 网络通信服务器框架 3.0.22 版本发布

acl 3.0.22 版本发布了,acl 是 one advanced C/C++ library 的简称,主要包括网络通信库以及服务器框架库等功能,支持 Linux/Windows/Solaris/FreeBsd/MacOS 平台;整个 acl 项目主要包含三...

郑树新
2014/12/16
2.5K
9
acl 网络通信服务器框架 3.1.0 版本发布

acl 3.1.0 版本发布了,acl 是 one advanced C/C++ library 的简称,主要包括网络通信库以及服务器框架库等功能,支持 Linux/Windows/Solaris/FreeBsd/MacOS 平台;整个 acl 项目主要包含三个...

郑树新
2015/02/08
2.9K
2
C++字符串库--vstring

VSTRING 是一个C++字符串库,提供动态字符串,兼容 char* ,Perl 类数组和散列,正则表达式对象。

叶秀兰
2014/01/08
921
0
acl 3.1.5 发布,跨平台网络通信与服务器编程框架

acl 3.1.5 版本发布了,acl 是 one advanced C/C++ library 的简称,主要包括网络通信库以及服务器框架库等功能,支持 Linux/Windows/Solaris/FreeBsd/MacOS 平台;整个 acl 项目主要包含三个...

郑树新
2016/04/16
2.5K
7

没有更多内容

加载失败,请刷新页面

加载更多

一个简单易用的Linux文本编辑器:nano的安装与使用

许多状况下咱们都必要编纂云主机里的文本情节,而现时用的比力多的文本编纂器是vim,这个估量许多人都以为很难用,这边伏笔VPS引荐一个简略易用的文本编纂器nano,比vim简略许多,很轻易上手...

shzwork
12分钟前
0
0
go recover

异常、错误常见语言处理 一般语言都有其错误处理方式,就以鄙人熟悉的php来距离吧。 PHP有多个级别的错误处理方式,以防止程序在还未正确执行完毕时,就造成了程序的提前结束。 try/catch/fi...

o0无忧亦无怖
31分钟前
0
0
玩转混合云+边缘计算,且看ZStack Mini!

文章导读:2019年4月16日,ZStack新品和合作伙伴战略发布会上,面向集团客户和边缘场景需求,ZStack重磅推出ZStack Mini超融合一体机(以下简称:ZStack Mini)和ZStack多云管理平台(以下简...

ZStack社区版
32分钟前
0
0
springboot 整合redis

springboot整合redis官方是有文档的: 英文看不懂可以翻译,代码应该看得懂, 这个是自动注入的。当然也可以xml注入,手动配置。 整合步骤: pom文件: <!-- spring boot web --> ...

jason_kiss
36分钟前
2
0
手机耗电问题,大部分是没有正确使用这个“锁”

当安卓设备闲置时,设备很快会进入休眠状态,以达到省电和减少CPU占用的目的。但有些应用在手机灭屏甚至系统休眠时,依然频繁占用CPU处理事件或唤醒屏幕提示用户消息,这类行为会导致手机耗电...

安卓绿色联盟
37分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部