Java 加速正则表达式

Java 加速正则表达式,java,regex,performance,Java,Regex,Performance,这是从SQL语句中提取表名的正则表达式: (?:\sFROM\s|\sINTO\s|\sNEXTVAL[\s\W]*|^UPDATE\s|\sJOIN\s)[\s`'"]*([\w\.-_]+) 它匹配一个标记,可以选择包含在[`'']中,前面是FROM等,周围是空格,但UPDATE没有前导空格 我们执行了很多正则表达式,这是最慢的一个,我不知道为什么。SQL字符串的大小可以达到4k,在2.2GHz i7 MBP上执行时间最长为0,35ms 这是一个缓慢的输入示例: 我们能做得更好吗?如果交替

这是从SQL语句中提取表名的正则表达式:

(?:\sFROM\s|\sINTO\s|\sNEXTVAL[\s\W]*|^UPDATE\s|\sJOIN\s)[\s`'"]*([\w\.-_]+)
它匹配一个标记,可以选择包含在
[`'']
中,前面是FROM等,周围是空格,但UPDATE没有前导空格

我们执行了很多正则表达式,这是最慢的一个,我不知道为什么。SQL字符串的大小可以达到4k,在2.2GHz i7 MBP上执行时间最长为0,35ms

这是一个缓慢的输入示例:


我们能做得更好吗?如果交替是一个问题,那么将其拆分为多个正则表达式也是一个选择。

Regex
优化是一个非常复杂的主题,应该借助一些工具来完成。例如,我喜欢用它来计算引擎为匹配
模式所需的步骤数到
有效载荷
。对于您的
模式
和给定示例,它将打印:

1 match, 22976 steps (~19ms)
首先,您可以始终将相似的部分分组到一个组中。例如,
加入
看起来相似,因此我们可以按如下方式编写正则表达式:

(?:\s(?:FROM|INTO|JOIN)\s|\sNEXTVAL[\s\W]*|^UPDATE\s)[\s`'"]*([\w\.-_]+)
对于上面的示例,打印:


试着找到一些在线工具来解释和优化正则表达式,比如计算引擎需要执行多少步。

因为匹配通常接近尾声,一种可能是基本上从尾声开始回溯,而不是从开头开始向前跟踪,这是一种类似于

^(?:UPDATE\s|.*(?:\s(?:(?:FROM|INTO|JOIN)\s|NEXTVAL[\s\W]*)))[\s`'\"]*([\w\.-_]+)
(154步)

当匹配存在时,这可能会快得多,但当没有匹配时,这只是一个中等程度的改进,因为模式必须一直回溯到开始(从步骤到步骤)

有一个:

如果存在一些边界,不要让引擎尝试匹配每个字符

尝试以下正则表达式(对给定的输入字符串执行大约2500个步骤):

注意:您需要的是第一个捕获组

根据注释,最终的正则表达式(比之前的干净正则表达式稍微慢一点):


您能提供预期的输入/输出吗?一些SQL字符串被截断,因为它们太长,然后它们根本没有表中的
。但是如果它们特别长,则很可能在字符串末尾附近有它,因为在开始时有大量自动生成的列定义。我建议将模式缩小到
(?:\s(?:(?:FROM | to | JOIN)\s | NEXTVAL)^UPDATE\s)\W*([\W.-]+)
,请参阅(12471对22976步)不应影响速度,但
[\s\W]
\W
相同,我希望您知道
[\W.-/code>包括所有字母、数字和
/:?[\]^_
。好的,没有人提到它,但是这里的正则表达式优化规则是为了避免随后无限量化的模式匹配相同的字符。当涉及到替换时,*确保替换不匹配相同位置的相同文本(即避免
(\sLl\s|sWw\s)
,使用
\s(Ll | Ww)\s
)我自己不知道SQL语法,所以我不知道这种模式必须考虑的陷阱或其他可能性,但可能有一个很好的模式涉及
(?:\S+AS\S+,)*
或类似的东西,在开始时消耗巨大的列的速度已经更快了,但由于匹配顺序已更改,它并不完全等效。例如,将其与旧的正则表达式进行比较,在旧正则表达式中,它匹配的是连接而不是FROM:
SELECT*FROM order\u refactor o LEFT JOIN order\u data od ON o.id=od.order\u id其中o.id=:id预期:“order\u refactor”但是:“order\u data”
I是否被定为“消耗巨大的列”,但是它稍微慢了一点。您确定在不同的输入stings上的性能吗?我在大量SQL语句中运行了它,正则表达式是完全等效的,但不幸的是平均来说稍微慢一点(0177对0179)。在对大量SQL语句进行测试时,这部分正则表达式可能不太重要。不过,我的答案不是最终的解决方案,而是如何找到最佳解决方案的过程。这一部分非常快,但…不起作用?有200多个匹配组,第一个组仅包含“选择”“。请记住最后一句话,你需要的是第一组。您需要迭代捕获组1的值。我看到您将正则表达式从
(?!from |改为| NEXTVAL | UPDATE | JOIN)\S*\S*\w+\w*(\w[\w\.-\u]*)
改为
(?:\S(?:((?:from | to | JOIN)/S | NEXTVAL)^UPDATE S)\w*([\w.-])
)。我试试看。好吧,平均速度是原来的两倍——不错!但不能很好地处理子选择。示例:
select*from(从PDMBOM2.materialalways materialwa0.name=?和materialwa0.revision=?)中选择不同的materialwa0.id作为col\u 0\u,其中rownum@MichaelBöckling I对管道右侧进行了更改。试试这个
^(?:UPDATE\s|.*(?:\s(?:(?:FROM|INTO|JOIN)\s|NEXTVAL[\s\W]*)))[\s`'\"]*([\w\.-_]+)
(?!FROM|INTO|NEXTVAL|UPDATE|JOIN)\S*\s*|\w+\W*(\w[\w\.-]*)
(?!(?:FROM|INTO|NEXTVAL|UPDATE|JOIN)\b)\S*\s*|\b(?:NEXTVAL\W*|\w+\s[\s`'"]*)([\[\]\w\.-]+)