redis下的字符串分割函数

5 篇文章 0 订阅

在看redis-cli.c的时候,遇到了字符串分割函数sdssplitargs,我想不就是字符串分割函数吗,我也会写,我到要看看自己写的东西与标准有何不同。

一个用C语言写的字符串分割函数需要考虑哪些问题呢?

1,分割的字符串用啥存储呢?答案是二重指针,相当于一个字符串数组;

2,使用啥函数解决从源字符串复制到新开辟的指针所指向的空间呢?strncpy;

3,函数的逻辑问题?嗯,如果遇到‘\0’可以看成是字符串的结束,如果是‘ ’可以看成token字符串的开始,这样可以记录每个token的位置。

代码展示如下:

#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>

int split_space(char **argvs, char* line){
	char *p = line;
	char *ps, *ptoken;
	int len, i = 0;
	while(*p){
		//从非空格开始
		while(isspace(*p)) ++p;
		ps = p;        //token起点
		while(!isspace(*p) && *p) ++p;
		len = p - ps;  //token长度
		ptoken = (char *)malloc(sizeof(char) * len);
		strncpy(ptoken, ps, len);
		argvs[i++] = ptoken;
	}
	return i;
}

void out_put(char **argvs, int l){
	int i = 0;
	for(i = 0; i < l; ++i){
		printf(":%s\n", argvs[i]);
	}
}

int main(){
	char **argvs;
	char *s = " ab cd ef";
	int len;
	//预先分配10个字符串指针
	argvs = (char **)malloc(sizeof(char *) * 10);

	len = split_space(argvs, s);
	out_put(argvs, len);
}

程序运行正常,可以正常根据空格分割字符串。那就好了,再看看redis这个东西的sdssplitargs做了什么。首先看看它的接口函数:

sds *sdssplitargs(const char *line, int *argc)

嗯,可以理解,redis的字符串用sds表示,返回值是sds数组,没毛病;输入为待检测字符串,与token个数指针(也就是要返回token个数),也没毛病。与自己的函数相比,它返回的是sds数组,我返回的是字符串数组罢了。

那再看看,它的内部实现,瞅了一眼,好像很多行代码的样子,所以它到底干了些啥?

sds *sdssplitargs(const char *line, int *argc) {
    *argc = 0;
    while(1) {
        /* skip blanks */
        while(*p && isspace(*p)) p++;
        if (*p) {
            /* get a token */
            int inq=0;  /* set to 1 if we are in "quotes" */
            int insq=0; /* set to 1 if we are in 'single quotes' */
            int done=0;

            if (current == NULL) current = sdsempty();
            while(!done) {
                //处理双引号
                if (inq) {
                    //处理16进制数字转换
                    if (*p == '\\' && *(p+1) == 'x' &&
                                             is_hex_digit(*(p+2)) &&
                                             is_hex_digit(*(p+3)))
                    {
                        unsigned char byte;

                        byte = (hex_digit_to_int(*(p+2))*16)+
                                hex_digit_to_int(*(p+3));
                        current = sdscatlen(current,(char*)&byte,1);
                        p += 3;
                    } else if (*p == '\\' && *(p+1)) {
                        //处理特殊字符
                        char c;

                        p++;
                        switch(*p) {
                        case 'n': c = '\n'; break;
                        ...
                        }
                        current = sdscatlen(current,&c,1);
                    } else if (*p == '"') {
                        /* closing quote must be followed by a space or
                         * nothing at all. */
                        if (*(p+1) && !isspace(*(p+1))) goto err;
                        done=1;
                    } else if (!*p) {
                        /* unterminated quotes */
                        goto err;
                    } else {
                        current = sdscatlen(current,p,1);
                    }
                } else if (insq) {
                    //处理单引号
                    if (*p == '\\' && *(p+1) == '\'') {
                        p++;
                        current = sdscatlen(current,"'",1);
                    } else if (*p == '\'') {
                        /* closing quote must be followed by a space or
                         * nothing at all. */
                        if (*(p+1) && !isspace(*(p+1))) goto err;
                        done=1;
                    } else if (!*p) {
                        /* unterminated quotes */
                        goto err;
                    } else {
                        current = sdscatlen(current,p,1);
                    }
                } else {
                    switch(*p) {
                    case '\n':
                        ...
                    case '\0':
                        done=1;
                        break;
                    case '"':
                        inq=1;
                        break;
                    case '\'':
                        insq=1;
                        break;
                    default:
                        current = sdscatlen(current,p,1);
                        break;
                    }
                }
                if (*p) p++;
            }
            /* add the token to the vector */
            vector = s_realloc(vector,((*argc)+1)*sizeof(char*));
            vector[*argc] = current;
            (*argc)++;
            current = NULL;
        } 
    }

err:
    ...
}

简要看一下,可以看出,自己分割字符串函数的思路并没有出错,与redis函数逻辑是相同的,只是它在原来函数基础上扩展了几个功能

1,可以剔除对应的引号;

2,可以转换16进制数字;

3,可以处理特殊字符?这里说明一下,如果在函数文本里输入"\n",或者'\n',函数会认为这是4个字母,我们经常用的printf函数自带了特殊字符识别功能,所以能根据输入"\n"换行;如果自己写的字符串分割函数想要实现特殊字符处理的话,还是要首先识别特殊字符的,然后再以‘\n’单个字符的格式添加到字符串中,才能实现换行操作。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在连接Redis时,可以使用连接字符串进行配置。连接字符串包括以下几个参数: - IP和端口:指定Redis服务器的IP地址和端口号,例如"127.0.0.1:6379"表示本地主机IP地址为127.0.0.1,端口号为6379。 - password:指定Redis服务器的密码,如果有密码设置,需要在连接字符串中添加"password=密码",例如"password=123456"表示密码为123456。 - connectTimeout:指定连接超时时间,单位为毫秒,表示在指定的时间内尝试连接Redis服务器,如果超时则连接失败。 - connectRetry:指定重试连接次数,表示在连接失败后进行重试连接的次数。 - syncTimeout:指定同步操作的默认超时时间,单位为毫秒,表示在执行同步操作时,如果超过指定的时间还未完成,则视为超时。 所以,一个Redis连接字符串的示例可以是:"RedisTest" WriteServer="127.0.0.1:6379,password=123456,connectTimeout=1000,connectRetry=1,syncTimeout=1000"。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* *2* [如何像连接SQL一样配置Redis连接字符串](https://blog.csdn.net/WuLex/article/details/119829164)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值