2022-09-06-Nginx中的正则表达式.md

背景

最近的业务需求需要对Apisix进行二次插件开发,实现对网络请求中汉语字段单独进行处理的目的。

类似的需求场景并不少见,插件开发使用lua语言,lua语言在nginx进行二次开发时能够使用ngx.re进行正则匹配,确定思路,直接开写。

已知,汉字的正则匹配应该这么写:

1
[\u4e00-\u9fa5]

如果在Java里面,这段代码应该是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexMatches {

    public static void main(String args[]) {
        String str = "123汉字测试test";
        String pattern = "[\u4e00-\u9fa5]";

        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(str);
        System.out.println(m.matches());
    }

}

在lua中写汉字正则匹配

初版代码大概类似这样

1
2
3
local rex = "[\u4e00-\u9fa5]"
local str = "123汉字测试test"
local m = ngx.re.match(str, rex) 

但是这串代码不work,没办法识别到字符串中的汉字。

遇事不决问google,找到了章亦春大佬13年回答的相关问题:https://groups.google.com/g/openresty/c/S1mwFQJm2SI?pli=1。

代码执行不符合预期的原因可以简单解释为,相对于我们经常熟悉的Java、JS正则使用方式,lua中的正则其实使用了另外一种语法格式。

这种语法格式要求我们将

1
[\u4e00]   写成   \x{u4e00}

常年写Java的人确实不知道regex竟然有不同的语法风格。so,到这里疑问就解决了,后面业务代码还有一些小的波折,最后封装了一个方法进行业务处理,方法会贴在文章的最后。

不同的REGEX引擎

regex的基础知识和不同引擎之间的差异无法通过一篇文章简单的描述清楚,这里仅提供查阅某一种语言或者工具对于regex支持、实现的方式

目前找到的最方便的网站是:regular-expressions.info

  1. 访问这个地址,可以看到左侧工具栏 Languages & Libraries分类,通过这个分类找到自己要使用的语言
  2. 点击左侧链接,页面会展示当前语言/工具的regex实现细节和使用,并且一般会有demo
  3. then,开始使用

参考网站资料

最终使用的代码(包含业务逻辑)

1
2
3
4
5
6
7
8
9
10
11
12
 for w in string.gmatch(value, '[%z-2794-44][28-91]*') do
                    -- 逐字符辨认,汉字时w=3
                    if count > 4 then
                        res = false;
                    end
                    if #w ~= 1 then
                        count = count + 1;
                    else
                        count = 0;
                    end
                end