一、概述
当我们在使用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
分享到:
相关推荐
`vstring.c`可能包含了对动态字符串(变长字符串)的操作,这种字符串允许在运行时改变其长度,相比于固定长度的字符串更灵活。 `intel_tex_layout.c`可能涉及到Intel处理器上的文本布局算法。文本布局是指确定文本...
这些函数覆盖了日期时间处理、随机数生成、字符串操作、文件读写、邮件发送、Excel操作等多个方面,极大地扩展了QTP的功能,使得自动化测试脚本编写更加灵活和高效。在实际的软件测试项目中,根据具体需求,可以通过...
- `encodeURI`通常需要调用两次,这是因为第一次编码后的字符串可能包含非ASCII字符,第二次编码可以确保所有字符都被正确编码。 - 编码后的字符串可以直接拼接到URL中。 #### 三、Java中的`URLDecoder.decode`方法...
VString.cxx
- `VString`: 需要排序的字符串数组。 - `Spl`: 分隔符。 - `Func`: 排序方式(升序或降序)。 - **用途**: 在需要对字符串进行排序处理时使用。 #### QTP自定义函数 ##### 1. `QTP_Small()` - **功能**: QTP...
首先,C#的字符串(String)类提供了丰富的操作方法,如Split、Join、Replace等,用于对输入的文本进行预处理。为了将横排文本转为竖排,开发者可能需要自定义一个方法,通过循环遍历字符并改变其排列顺序。同时,考虑...
下面是一个ASP函数`DSConvert`,它可以根据传入的参数`vFlag`将字符串中的全角字符转换为半角字符或者反之: ```vbscript Function DSConvert(vString, vFlag) ' vFlag为0时,表示从全角转为半角;其他值表示从...
- 实验涉及到使用基本数据类型(如int)和类(如Math)的方法,如`Integer.parseInt()`将字符串转换为整数,`Math.random()`生成随机数。 6. **数组操作**: - 实验二中,创建了一个一维数组并用`Math.random()`...
其中,字符型(Characters)用来存储文本数据,布尔型(Boolean)用来表示逻辑值(真/假),日期和时间型(Date&Time)用来存储日期和时间信息,整数型(Integer)用来存储数值型数据,而可变字符串(VSTRING)则...
- 线程是操作系统分配CPU时间的基本单位,每个进程至少包含一个线程。 - 在多线程应用程序中,多个线程可以并发执行,提高程序的响应性和效率。 - Delphi提供多种创建线程的方式,包括`TThread`类和原生的`...
import AiSoft.OwnHome.Common.VString; import AiSoft.OwnHome.Opreation.ArticleDao; public class DetailServlet extends HttpServlet { /** * Constructor of the object. */ public DetailServlet() { ...