Redis源码分析(二十三)——通用工具算法util

来源:互联网 发布:破解软件下载 编辑:程序博客网 时间:2024/05/20 14:25

通用工具类算法是一些常见的辅助处理算法。在此主要分析正则表达式的匹配原理,以及字符串与长整型之间的相互转换。 


正则表达式的匹配原理:

通过这次分析,才算正真懂了正则表达式匹配的原理和具体的处理过程,也算是一大收获。

函数stringmatchlen:

支持glob-style的通配符格式,如*表示任意一个或多个字符,?表示任意字符,[abc]表示方括号中任意一个字母。
将给定字符串与给定模式匹配,匹配返回1,否则返回0

int stringmatchlen(const char *pattern, int patternLen,        const char *string, int stringLen, int nocase){    while(patternLen) {        switch(pattern[0]) {        case '*':  //模式的当前字符为*, 则只需要模式中连续*以后的部分与给定string的某后部分匹配即可            while (pattern[1] == '*') {                pattern++;                patternLen--;            }            if (patternLen == 1)  //到此,说明模式全为*, 当然匹配                return 1; /* match */            while(stringLen) {   //模式前部分全为*, 则只需后部分与string 的某后部分匹配即可,                      //依次往后查找string中的该“某后部分”,直到匹配,或者到尾部                if (stringmatchlen(pattern+1, patternLen-1,                            string, stringLen, nocase))                    return 1; /* match */                string++;                stringLen--;            }            return 0; /* no match */            break;        case '?':    //模式的当前字符为? ,则直接跳过string的当前字符,从下一字符开始判断            if (stringLen == 0)                return 0; /* no match */            string++;            stringLen--;            break;        case '[':   //模式的当前字符为[  ,范围,需要根据下一字符确定是为为 ^        {            int not, match;            pattern++;            patternLen--;            not = pattern[0] == '^';            if (not) {                pattern++;                patternLen--;            }            match = 0;            while(1) {                if (pattern[0] == '\\') {                    pattern++;                    patternLen--;                    if (pattern[0] == string[0])                        match = 1;                } else if (pattern[0] == ']') { //[]里面为空                    break;                } else if (patternLen == 0) {                    pattern--;                    patternLen++;                    break;                } else if (pattern[1] == '-' && patternLen >= 3) {//如[1-8]:即1到8中的任意一个字符 ,只要string当前字符在此范围内                    int start = pattern[0];                    int end = pattern[2];                    int c = string[0];                    if (start > end) {                        int t = start;                        start = end;                        end = t;                    }                    if (nocase) {                        start = tolower(start);                        end = tolower(end);                        c = tolower(c);                    }                    pattern += 2;                    patternLen -= 2;                    if (c >= start && c <= end)                        match = 1;                } else {                    if (!nocase) {                        if (pattern[0] == string[0])                            match = 1;                    } else {                        if (tolower((int)pattern[0]) == tolower((int)string[0]))                            match = 1;                    }                }                pattern++;                patternLen--;            }            if (not)                match = !match;            if (!match)                return 0; /* no match */            string++;            stringLen--;            break;        }        case '\\':            if (patternLen >= 2) {                pattern++;                patternLen--;            }            /* fall through */        default: // 如果没有正则表达式的关键字符,则直接比较             if (!nocase) {                if (pattern[0] != string[0])                    return 0; /* no match */            } else {                if (tolower((int)pattern[0]) != tolower((int)string[0]))                    return 0; /* no match */            }            string++;            stringLen--;            break;        }        pattern++;        patternLen--;        if (stringLen == 0) {            while(*pattern == '*') {                pattern++;                patternLen--;            }            break;        }    }    if (patternLen == 0 && stringLen == 0)//完全匹配        return 1;    return 0;}


字符串与长整型之间的相互转换:

 数值转换为字符串:    注意作者的具体做法,值得深思与学习!

 我们一般的做法是 每次除以10 取余,再将余数转换为对应的字符,如此从低位到高位逐位处理。
 在这作者提供了更好的做法 由于longlong类型是很长的数值,因此每次除以10,逐位处理需要进行很多次,所以采取除以100,每次处理两位,如此一来节约了一半的时间; 另外,作者将所有的两位数00 到99,所对应的字符全部先存放到一个字符串表中,后面只需要直接查表取出对应的字符即可,而不需要每次都去转换。   这再次大大的提高了效率啊!

int ll2string(char* dst, size_t dstlen, long long svalue) {//00到99的数字对应的字符串, 直接查表,而不是每次都将整数转换为字符串    static const char digits[201] =        "0001020304050607080910111213141516171819"        "2021222324252627282930313233343536373839"        "4041424344454647484950515253545556575859"        "6061626364656667686970717273747576777879"        "8081828384858687888990919293949596979899";    int negative;    unsigned long long value;    uint32_t next;    /* The main loop works with 64bit unsigned integers for simplicity, so     * we convert the number here and remember if it is negative. */ //把负数转换为正数处理,加上一位的符号    if (svalue < 0) {        if (svalue != LLONG_MIN) {            value = -svalue;        } else {            value = ((unsigned long long) LLONG_MAX)+1;        }        negative = 1;    } else {        value = svalue;        negative = 0;    }    /* Check length. */    uint32_t const length = digits10(value)+negative;    if (length >= dstlen) return 0;//由于在字符串中末尾需要包含‘\0’,因此所需的字符串的长度至少要比ll长度大1    /* Null term. */    next = length;    dst[next] = '\0';    next--;       while (value >= 100) {   //由于每次都是处理的除以100的余数,即ll的低两位,因此从字符串的末尾向前开始填充        int const i = (value % 100) * 2;        value /= 100;        dst[next] = digits[i + 1];//直接查表,取得对应的字符        dst[next - 1] = digits[i];        next -= 2;    }    /* Handle last 1-2 digits. */    if (value < 10) {        dst[next] = '0' + (uint32_t) value;    } else {        int i = (uint32_t) value * 2;        dst[next] = digits[i + 1];        dst[next - 1] = digits[i];    }    /* Add sign. *///若为负数,在字符串开头加上负号标志    if (negative) dst[0] = '-';    return length;}


字符串转换为longlong:

 //字符串转换为longlong:从字符串的第一位开始逐位取出,(第一位为longlong的最高位)。每次将ll值乘以10,然后将新取出的低位作为各位数加到ll值上int string2ll(const char *s, size_t slen, long long *value) {    const char *p = s;    size_t plen = 0;    int negative = 0;    unsigned long long v;    if (plen == slen)        return 0;    /* Special case: first and only digit is 0. */    if (slen == 1 && p[0] == '0') {        if (value != NULL) *value = 0;        return 1;    }    if (p[0] == '-') {        negative = 1;        p++; plen++;        /* Abort on only a negative sign. */        if (plen == slen)            return 0;    }    /* First digit should be 1-9, otherwise the string should just be 0. */    if (p[0] >= '1' && p[0] <= '9') {        v = p[0]-'0';        p++; plen++;    } else if (p[0] == '0' && slen == 1) {        *value = 0;        return 1;    } else {        return 0;    }    while (plen < slen && p[0] >= '0' && p[0] <= '9') {        if (v > (ULLONG_MAX / 10)) /* Overflow. */            return 0;        v *= 10;        if (v > (ULLONG_MAX - (p[0]-'0'))) /* Overflow. */            return 0;        v += p[0]-'0';        p++; plen++;    }    /* Return if not all bytes were used. */    if (plen < slen)        return 0;    if (negative) {        if (v > ((unsigned long long)(-(LLONG_MIN+1))+1)) /* Overflow. */            return 0;        if (value != NULL) *value = -v;    } else {        if (v > LLONG_MAX) /* Overflow. */            return 0;        if (value != NULL) *value = v;    }    return 1;}



0 0
原创粉丝点击