【问题标题】:Why do these regular expressions execute slowly in Java?为什么这些正则表达式在 Java 中执行缓慢?
【发布时间】:2011-03-08 20:10:15
【问题描述】:

我正在尝试使用正则表达式来确定用户在文本框中输入输入时应用的格式。
正则表达式如下:

(\\s?[" + alphabet + "]{9,9})+

确定输入是否是给定字母表中长度为 9 的一个或多个字符串,可能由空格分隔。

(>[\\w\\s]+\\n[" + alphabet + "\\s]+)+

检查输入是否在FASTA format

inputString.matches(regexString) 匹配时,正则表达式运行得非常慢。这是为什么呢?

我认为这可能是由于 Java 存储了所有潜在的匹配项(此时我不需要),但在每个括号中添加 ?: 会破坏正则表达式。这应该怎么做?

谢谢,

马丁

编辑 1: 我无法重现此问题 - 它只发生在一台计算机上。这可能表明该特定 VM 设置存在问题。
我们需要更强大的东西,因此我们将以不同的方式实现它。我选择 Joel 的答案是正确的,因为我相信 Pattern 中的一些特殊情况可能是原因。

【问题讨论】:

  • 您可能尝试与每个输入字符串匹配多少种模式?模式是动态的还是静态的?
  • @Joel 只有这两种模式。它们是静态的。使用 String.matches 每次都会导致编译,但即使是一次匹配模式也需要很长时间(> 10s 大约 300 个字符输入)
  • 你能定义“非常慢”吗?
  • @matt 在我的机器(Intel i7 @ 2.67 GHz)上匹配长度为 300 的输入字符串需要超过 10 秒
  • 请发布一个独立的程序,我们可以运行它来看看这种情况发生!

标签: java regex performance pattern-matching


【解决方案1】:

string.matches() 每次执行时都会编译正则表达式。相反,请查看 Pattern/Matcher 类,它们允许您缓存预编译的正则表达式。

如果您不需要匹配结果,另一件事是使用非捕获正则表达式组。

【讨论】:

  • 我只调用了matches() 一次,所以这应该不是问题。正则表达式在输入量很小的情况下表现良好,但在输入超过 200 个字符时速度非常慢。我无法让非捕获组工作 - 你能举个例子吗?
  • 切换到非捕获组不会给您带来 1000 倍的改进。不过,这就是你的做法 - 把 ?: 放在左括号之后 - 例如: (?:\\s?[" + alphabet + "]{9,9})+
【解决方案2】:

如果您有许多不同的正则表达式模式与相同的输入进行匹配以尝试对输入进行分类,那么您最好使用像 JFlex 这样的词法分析器生成器。

可以在here 中找到通常用于编译器构造的其他基于 Java 的词法分析器和解析工具。

【讨论】:

  • 这些工具很有用,谢谢!但我只有 2 个正则表达式,这应该很简单 - 我认为使用 JFlex 之类的会过大。
  • @Martin - 在这种情况下,听起来 JFlex 之类的东西比通常需要的要多。但是,在更仔细地查看您正在使用的正则表达式时,您的案例可能会暴露 Pattern 类如何编译其分析器的一些退化案例。可能值得尝试 JFlex,看看它是否可以为这种情况生成更严格的分析器。
【解决方案3】:

这可能无法解释您的特定问题。但是,一旦我深入了解 JDK 的正则表达式实现,我就对它的简单感到惊讶。它并没有真正构建一个在每个输入字符处前进的状态机。我想他们有他们的理由。

在您的情况下,自己手动编写解析非常容易。人们害怕这样做,手动编码这些微小的步骤似乎“愚蠢”,并且人们认为已建立的库必须做一些出色的技巧来超越本土解决方案。这不是真的。很多情况下,我们的需求比较简单,DIY起来更简单快捷。

【讨论】:

  • Pattern.compile() 方法确实构建了 Pattern.Node 类的后代的状态机。你的意思是它构建了一个 NFA 自动机而不是 DFA 吗?这是大多数功能丰富的正则表达式引擎使用的设计,以速度换功能。这是一篇解释这一点并提出替代方案的文章:weblogs.java.net/blog/2006/03/27/faster-java-regex-package
猜你喜欢
  • 2020-11-27
  • 1970-01-01
  • 2019-03-12
  • 1970-01-01
  • 1970-01-01
  • 2016-07-14
  • 2015-02-11
  • 2014-01-23
  • 1970-01-01
相关资源
最近更新 更多