如何存储大量正则表达式并找出与给定字符串匹配的表达式?
逆向匹配正则表达式的优化方案
核心思路
平时都是用正则找匹配的字符串,你现在要反过来用字符串找匹配的正则,核心就是要少做无用功,别傻乎乎把所有正则挨个跑一遍,先过滤掉肯定不沾边的,再对剩下的做匹配。
实用优化方案
1. 先分组再过滤
- 给你的正则按特征归类,比如把开头是
http://的放一组,包含@的放一组,前缀长度是5的放一组。 - 拿到目标字符串后,先提取它的特征:比如开头是
ftp://,那直接跳过http://那组;字符串里没@,就跳过带@的正则组。这样一下子就能排除一大波不可能匹配的正则。
2. 提前编译正则
- 不管用哪种语言,都把所有正则提前编译成可复用的对象(比如Python里用
re.compile(),Java里用Pattern),别每次匹配都重新编译一遍,太费CPU。 - 用个字典存起来,键是正则字符串,值是编译好的对象,要用的时候直接拿出来用就行。
3. 前缀树缩小范围
- 如果你的正则大多有固定前缀(比如
user_、order_这类),可以把这些前缀做成前缀树。 - 拿目标字符串的前缀去树里找,找到所有对应前缀的正则,只对这些正则做匹配,范围一下子就小了很多。
4. 数据库加特征字段过滤
- 要是你还是想用数据库存正则,给表加几个特征字段,比如
prefix(正则的固定前缀)、has_special_char(有没有特殊字符)。 - 查询的时候先靠这些字段筛出可能匹配的正则,再拿出来做匹配,不用把所有正则都捞出来。
关于Elasticsearch的用法
ES本身不能直接用字符串匹配存储的正则,但可以用脚本查询实现:
- 写个Painless脚本,遍历存储的正则字段,用
Pattern.matcher(你的字符串).matches()判断是否匹配。 - 但这种方式性能一般,适合正则数量不是特别多的场景,最好先分组过滤缩小范围再用脚本查。
总结下
如果正则数量特别多(十万级以上),优先用分组+前缀树的组合,先过滤再匹配;数量中等的话,提前编译加数据库特征过滤就够了;ES可以用,但得做好前置过滤,不然性能拉胯。
内容的提问来源于stack exchange,提问作者BBloggsbott
相关产品推荐
相关产品推荐

