[redis]Glob模式匹配

前言

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 命令为例
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/a374826954/article/details/107748722