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
- Redis源码分析(二十三)——通用工具算法util
- Redis源码分析(二十三)--- CRC循环冗余算法和RAND随机数算法
- Redis源码分析(十三)——集合类型t_set
- Redis源码分析(十三)--- redis-benchmark性能测试
- Redis源码分析(二)——链表adlist
- Redis源码分析(二十)——事件ae
- Redis源码分析(二)——Redis数据结构-链表
- Java-Collection源码分析(十三)——TreeMap
- Redis源码分析(二十四)--- tool工具类(2)
- 结合redis设计与实现的redis源码学习-26-工具函数(Util.h/.c)
- Redis Sentinel源码分析(二)
- ExtJs源码分析与学习—工具类Ext.util.TextMetrics
- Redis源码分析(二十一)——慢查日志slow_log
- Redis源码分析(二十二)——CRC循环冗余校验
- Redis源码分析(二十四)——客户端与服务器
- Redis源码分析(十一)——Redis数据库db
- Redis源码分析(二)--结构体分析(1)
- redis源码分析(二)、redis源码分析之sds字符串
- Myeclipse搭建Maven
- 在Spring中使用Hessian Remoting技
- lua中的require机制
- 面试题 0到N的所有数按字典序输出
- 收藏博客
- Redis源码分析(二十三)——通用工具算法util
- 云风blog Ejoy2D 开源
- JS检测浏览器Adobe Reader插件(转)
- 用于转换PDF格式的转换器
- 简单工厂模式
- dozer-初识
- BZOJ 1412 ZJOI 2009 狼和羊的故事 最小割
- java时间格式转换
- 又学习一点php垃圾回收机制之simple_html_dom库