设为首页 加入收藏

TOP

C语言编程笔记丨SDS:一个简易动态字符串库(三)
2019-04-01 22:08:12 】 浏览:416
Tags:语言编程 笔记 SDS 一个 简易 动态 字符串
; output
> -my string-

基本上,sdstrim()把要裁剪的SDS字符串作为第一个参数,并且带有一个以空字符终结的字符集, 它们会被从字符串的左边或右边去除。字符只要不被裁剪字符列表以外的字符隔开,就会被去除:这是为什么“my”和“string”中间的空格在上面的例子中被保留。

取得区间也类似,但不是取得一组字符,而是在字符串内取得表示开始和结束的索引,由0起始,来取得将被保留的区间。

sds s = sdsnew("Hello World!");sdsrange(s,1,4);printf("-%s-\n");

output> -ello

索引可以为负,来指定一个起始于字符串末尾的位置,因此-1表示最后一个字符,-2表示倒数第二的,以此类推。

sds s = sdsnew("Hello World!");sdsrange(s,6,-1);printf("-%s-\n");sdsrange(s,0,-2);printf("-%s-\n");

output> -World!-output> -World-

当实现网络服务器处理一个协议或者发送消息时,sdsrange()会非常有用。例如,下面的代码用来实现节点间的Redis Cluster消息总线的写处理:

void clusterWriteHandler(..., int fd, void *privdata, ...) {

    clusterLink *link = (clusterLink*) privdata;

    ssize_t nwritten = write(fd, link->sndbuf, sdslen(link->sndbuf));

    if (nwritten <= 0) {

        /* Error handling... */

    }

    sdsrange(link->sndbuf,nwritten,-1);

    ... more code here ...}

每当我们需要发送消息的目标节点的socket是可写的时候,我们尝试写入尽可能多的字节,我们用?sdsrange()从缓冲中移除已经发送的部分。

给发送到某个集群节点的新消息排队的函数就只是用sdscatlen()来把更多的数据放到发送缓冲中去。

注意,Redis Cluster总线实现了一个二进制的协议,因为SDS是二进制安全,所以这不会造成问题。所以SDS的目标不仅是为C程序员提供一个高层字符串API,还提供了易于管理的动态分配缓冲。

字符串复制

最危险、最恶名的C标准库函数可能就是strcpy了。所以可能有些有趣的是,在更好设计的动态字符串库的环境中,复制字符串的概念几乎是无关紧要的。通常你做的就是创建一个字符串,内容由你定,或者根据需要连接更多内容。

然而,SDS以一个有利于高效重要的代码段的字符串复制函数为特性。但是我猜它的实用性是有限的,因为这个函数从来没在50千行代码所组成的Redis代码库中被调用。

sds sdscpylen(sds s, const char *t, size_t len);sds sdscpy(sds s, const char *t);

SDS字符串复制函数叫sdscpylen,像这样调用:

s = sdsnew("Hello World!");s = sdscpylen(s,"Hello Superman!",15);

正如你能看到的,这个函数接收SDS字符串s作为输入,但也返回一个SDS字符串。这对很多修改字符串的SDS函数来说很普遍,用这个方法,返回的SDS字符串可能是基于原来的那个修改的,或者一个新分配的(比如旧的SDS字符串没有足够空间时)。

sdscpylen只是用由指针和长度参数传递的新数据,替换掉在旧SDS字符串里的内容。还有一个类似的函数叫sdscpy,不需要长度参数,但是要求带有空字符终结的字符串。

你可能会想,为什么SDS库需要一个字符串复制函数,你可以简单地从零开始创建一个新的SDS字符串,用新的值,而非复制一个存在的SDS字符串的值。理由是效率:sdsnewlen()总是分配一个新的字符串,而sdscplylen()会尽量重用已存在的字符串,如果有足够的空间,就用用户指定的新内容,只在必要时分配新的。

引用字符串(Quoted String)

为了给程序用户提供的输出,或者为了调试的目的,将一个可能包含二进制数据或者特殊字符的字符串转换成引用的字符串通常是很重要的。这里的引用字符串,意思是程序代码里的字符串文字上的一般形式。然而今天,这个形式也是著名的串行化格式的一部分,如JSON和CSV,所以它显然偏离了在程序的源代码中表现文字上的字符串这一简单的目标。

下面是一个引用字符串文面的例子:

"\x00Hello World\n"

第一个字节是一个0字节,当最后一个字节是一个换行,所以共有两个非字母的字符在这个字符串里。

SDS使用一个连接函数,把表示输入字符串的引用字符串,连接到一个已存在的字符串,来达到这个目的。

sds sdscatrepr(sds s, const char *p, size_t len);

scscatrepr()repr表示representation)遵从通常的SDS字符串函数规则,接收一个字符指针和一个长度参数,所以你可以用它来处理SDS字符串,或者一般的使用strlen()作为len参数的C字符串,或者二进制数据。下面是一个使用例子:

sds s1 = sdsnew("abcd");sds s2 = sdsempty();s[1] = 1;s[2] = 2;s[3] = '\n';s2 = sdscatrepr(s2,s1,sdslen(s1));printf("%s\n", s2);

output> "a\x01\x02\n"

这是sdscatrepr()使用的规则:

(1)\和“用backslash引用。

(2)能引用特殊字符’\n’, ‘\r’, ‘\t’, ‘\a’以及’\b’

(3)所有其他不能通过isprint测试的不可打印字符在\x..格式里被引用,就是backslash后跟x,后跟2位十六进制数字表示字符串的字节数值。

(4)这个函数总是加上初始的和最后的双引号字符。

有一个SDS函数能处理逆转换,在下面的语汇单元化(Tokenization)的篇幅里有记述

语汇单元化(Tokenization)

语汇单元化是一个把大字符串分割成小字符串的过程。在这个特定的例子中,指定另一个字符串作为分隔符来执行分割。例如,在下面的字符串,有两个子字符串被|-|分割符分割:

foo|-|bar|-|zap

一个更常用的由一个字符组成的分割符是逗号:

foo,bar,zap

处理一行内容来获得组成它的子字符串在许多程序中是很有用的,所以SDS提供了一个函数,给定一个字符串和一个分割符,返回一个SDS字符串的数组。

sds *sdssplitlen(const char
首页 上一页 1 2 3 4 5 下一页 尾页 3/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇C++编程丨C++11的指针 下一篇第一章:UNIX基础知识

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目