[redis]Glob模式匹配
前言
Glob模式匹配,它不像正则表达式这样具有丰富的语法,但是,它是一种相当简洁高效的一种模式匹配。代码简单,规则简单,因此其运行效率同样非常高效。其广泛应用于不同的系统,例如我们常用的Linux ls 命令。
规则
通配符 | 描述 |
---|---|
* | 匹配任意长度字符 |
? | 匹配一个字符 |
\\ | 匹配转义符 \ |
[a-z] | 匹配大于等于a,小于等于z;适用任何字符 |
[0123456789] | 匹配大于等于0,小于等于9;相当于[0-9] |
[^] | 非,匹配不相等字符 |
[^a-z] | 不匹配大于等于a,小于等于z;适用任何字符 |
[\\] | 匹配转义符 |
用处
我们学了这种模式之后,会在实际工作中用在什么地方呢?以redis为例
- 发布订阅系统频道的匹配,如果某一方订阅了模式频道,当前发布方发布信息时,只要匹配到这个模式频道,就会向该方发送消息
- ACL(Access Control List)系统,匹配某个用户是否某些命令的权限
所以在实际工作中
- 可以用于命令系统的设计,例如游戏中的GM命令等
- 规则匹配,例如在cdn中,线路根据区域分发
代码
以下是在redis中的源码,其实整体的代码还是比较容易理解,主要就循环每一个字符,处理规则中的特殊字符,如果发现是’*’,就去递归。
/* Glob-style pattern matching. */ int stringmatchlen(const char *pattern, int patternLen, const char *string, int stringLen, int nocase) { while(patternLen && stringLen) { switch(pattern[0]) { case '*': while (patternLen && pattern[1] == '*') { pattern++; patternLen--; } if (patternLen == 1) return 1; /* match */ while(stringLen) { if (stringmatchlen(pattern+1, patternLen-1, string, stringLen, nocase)) return 1; /* match */ string++; stringLen--; } return 0; /* no match */ break; case '?': string++; stringLen--; break; case '[': { int not, match; pattern++; patternLen--; not = pattern[0] == '^'; if (not) { pattern++; patternLen--; } match = 0; while(1) { if (pattern[0] == '\\' && patternLen >= 2) { pattern++; patternLen--; if (pattern[0] == string[0]) match = 1; } else if (pattern[0] == ']') { break; } else if (patternLen == 0) { pattern--; patternLen++; break; } else if (patternLen >= 3 && pattern[1] == '-') { 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; }
例子
以Linux ls 命令为例