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

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


正则表达式的匹配原理:

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

函数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;
}



发布了93 篇原创文章 · 获赞 3 · 访问量 7万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章