Java正则表达式库是否针对任何字符进行优化。*?
我有一个匹配正则表达式的包装类。 显然,你将正则表达式编译成这样的Pattern
。
Pattern pattern = Pattern.compile(regex);
但是假设我使用.*
来指定任意数量的字符。 所以它基本上是一个通配符。
Pattern pattern = Pattern.compile(".*");
模式是否优化以始终返回true而不是真正计算任何东西? 或者我应该让我的包装器实现该优化? 我这样做是因为我可以在一个过程中轻松处理数十万个正则表达式操作。 如果正则表达式参数为null,我将其合并为.*
在你的情况下,我可以使用占有量词来避免任何回溯:
.*+
Java模式匹配引擎可以使用多种优化,并可以自动应用它们。
这就是Cristian Mocanu在他的Java优化正则表达式中写的类似于.*
的案例:
Java正则表达式引擎无法优化表达式
.*abc.*
。 我预计它会在输入字符串中搜索abc
并很快报告失败,但事实并非如此。 在相同的输入字符串上,使用String.indexOf("abc")
比我改进的正则表达式快三倍。 似乎只有当已知字符串位于其开头或其内部的预定位置时,引擎才能优化此表达式。 例如,如果我将表达式重新编写为.{100}abc.*
,引擎将匹配它的速度提高十倍以上。 为什么? 因为现在强制字符串abc
位于字符串内的已知位置(之前应该只有一百个字符)。
来自同一来源的Java正则表达式优化的一些提示 :
- 如果正则表达式包含必须存在于输入字符串中的字符串(否则整个表达式将不匹配),引擎有时可以首先搜索该字符串,如果找不到匹配则报告失败,而不检查整个正则表达式。
- 另一种自动优化正则表达式的非常有用的方法是让引擎根据正则表达式检查输入字符串的长度与预期长度的关系。 例如,表达式
\d{100}
在内部进行了优化,如果输入字符串的长度不是100个字符,则引擎将在不评估整个正则表达式的情况下报告失败。 - 不要在分组或替换中隐藏强制字符串,因为引擎将无法识别它们。 如果可能,指定要匹配的输入字符串的长度也很有帮助
- 如果要在程序中多次使用正则表达式,请确保使用
Pattern.compile()
而不是更直接的Pattern.matches()
来编译模式。 - 还要记住,通过调用方法
reset()
,可以将Matcher
对象重用于不同的输入字符串。 - 谨防交替。 像
(X|Y|Z)
这样的正则表达式因为速度慢而闻名,所以请注意它们。 首先,交替顺序计数,因此将更常见的选项放在前面,这样它们可以更快地匹配。 另外,尝试提取常见的模式; 例如,代替(abcd|abef)
使用ab(cd|ef)
。 - 每当你使用否定的字符类来匹配别的东西时,使用所有格量词:而不是
[^a]*a
使用[^a]*+a
。 - 不匹配的字符串可能会导致代码比包含匹配的代码更频繁地冻结。 请记住始终首先使用非匹配字符串测试正则表达式!
- 谨防已知错误#5050507 (当正则表达式
Pattern
类抛出StackOverflowError时 ),如果遇到此错误,请尝试重写正则表达式或将其拆分为多个子表达式并单独运行它们。 后一种技术有时甚至可以提高性能。 -
而不是懒惰的点匹配,使用淬火贪婪的令牌(例如
(?:(?!something).)*
)或展开循环技术 (今天为它推倒,不知道为什么)。遗憾的是,您无法始终依赖引擎来优化正则表达式。 在上面的示例中,正则表达式实际上匹配得非常快,但在许多情况下表达式太复杂,输入字符串太大,引擎无法优化。