前言
Glob模式匹配,它不像正则表达式这样具有丰富的语法,但是,它是一种相当简洁高效的一种模式匹配。代码简单,规则简单,因此其运行效率同样非常高效。其广泛应用于不同的系统,例如我们常用的Linux ls 命令。
作者个人课堂:https://study.163.com/instructor/1385962921.htm
规则
通配符 | 描述 |
---|---|
* | 匹配任意长度字符 |
? | 匹配一个字符 |
\\ | 匹配转义符 \ |
[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 命令为例