我有一个用于匹配正则表达式的包装类。显然,您将正则表达式编译为Pattern
,就像这样。
Pattern pattern = Pattern.compile(regex);
但是假设我使用.*
来指定任意数量的字符。所以它基本上是一个通配符。
Pattern pattern = Pattern.compile(".*");
模式是否优化以始终返回true而不是真正计算任何东西?或者我应该让我的包装器实现该优化?我这样做是因为我可以在一个过程中轻松处理数十万个正则表达式操作。如果正则表达式参数为null,我将其合并为.*
答案 0 :(得分:3)
在你的情况下,我可以使用占有量词来避免任何回溯:
.*+
Java模式匹配引擎可以使用多种优化方法,并可以自动应用它们。
以下是与.*
类似的案例的Cristian Mocanu's writes in his Optimizing regular expressions in Java:
Java正则表达式引擎无法优化表达式
.*abc.*
。我希望它会在输入字符串中搜索abc
并快速报告失败,但事实并非如此。在相同的输入字符串上,使用String.indexOf("abc")
比我改进的正则表达式快三倍。似乎只有当已知字符串位于其开头或其内部的预定位置时,引擎才能优化此表达式。例如,如果我将表达式重新编写为.{100}abc.*
,则引擎将匹配它的速度提高十倍以上。为什么?因为现在强制字符串abc
位于字符串内的已知位置(之前应该只有一百个字符)。
部分hints on Java regex optimization from the same source:
\d{100}
在内部进行了优化,如果输入字符串的长度不是100个字符,引擎将报告失败而不评估整个正则表达式。Pattern.compile()
而不是更直接的Pattern.matches()
来编译模式。 Matcher
将reset()
对象重新用于不同的输入字符串。(X|Y|Z)
这样的正则表达式因为速度慢而闻名,所以请注意它们。首先,交替顺序计数,因此将更常见的选项放在前面,以便更快地匹配。另外,尝试提取常见的模式;例如,而不是(abcd|abef)
使用ab(cd|ef)
。 [^a]*a
使用[^a]*+a
。Pattern
类抛出 StackOverflowError 时),如果遇到此错误,请尝试重写正则表达式或将其拆分为多个子表达式并单独运行它们。后一种技术有时甚至可以提高性能。使用驯化的贪婪令牌(例如(?:(?!something).)*
)或unrolling the loop techinque(今天为它投票,不知道为什么),而不是懒人点匹配。
不幸的是,您不能依赖引擎来优化正则表达式。在上面的例子中,正则表达式实际上匹配得非常快,但在很多情况下表达式太复杂,输入字符串太大而引擎无法优化。