Java正则表达式库是否针对任何字符进行优化。*?

时间:2015-11-19 15:33:13

标签: java regex

我有一个用于匹配正则表达式的包装类。显然,您将正则表达式编译为Pattern,就像这样。

Pattern pattern = Pattern.compile(regex);

但是假设我使用.*来指定任意数量的字符。所以它基本上是一个通配符。

Pattern pattern = Pattern.compile(".*");

模式是否优化以始终返回true而不是真正计算任何东西?或者我应该让我的包装器实现该优化?我这样做是因为我可以在一个过程中轻松处理数十万个正则表达式操作。如果正则表达式参数为null,我将其合并为.*

1 个答案:

答案 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()来编译模式。
  • 另请注意,您可以通过调用方法Matcherreset()对象重新用于不同的输入字符串。
  • 谨防交替。像(X|Y|Z)这样的正则表达式因为速度慢而闻名,所以请注意它们。首先,交替顺序计数,因此将更常见的选项放在前面,以便更快地匹配。另外,尝试提取常见的模式;例如,而不是(abcd|abef)使用ab(cd|ef)
  • 每当您使用否定字符类来匹配其他内容时,请使用所有格量词:而不是[^a]*a使用[^a]*+a
  • 不匹配的字符串可能会导致代码比包含匹配项的代码更频繁地冻结。 请务必先使用不匹配的字符串测试正则表达式!
  • 小心known bug #5050507(当正则表达式Pattern类抛出 StackOverflowError 时),如果遇到此错误,请尝试重写正则表达式或将其拆分为多个子表达式并单独运行它们。后一种技术有时甚至可以提高性能。
  • 使用驯化的贪婪令牌(例如(?:(?!something).)*)或unrolling the loop techinque(今天为它投票,不知道为什么),而不是懒人点匹配。

      

    不幸的是,您不能依赖引擎来优化正则表达式。在上面的例子中,正则表达式实际上匹配得非常快,但在很多情况下表达式太复杂,输入字符串太大而引擎无法优化。