1

我注意到,当我在文本上匹配如下正则表达式时,它比没有前后 ( .*) 部分的正则表达式要慢得多。我在 perl 上做了同样的事情,发现对于 perl 它几乎没有什么区别。有没有办法优化"(.*)someRegex(.*)"java的原始正则表达式?

Pattern p = Pattern.compile("(.*)someRegex(.*)");
Matcher m = p.matcher("some text");
m.matches();

Pattern p = Pattern.compile("someRegex");
Matcher m = p.matcher("some text");
m.matches();

编辑:这是一个具体的例子:

(.*?)<b>\s*([^<]*)\s*<\/b>(.*)
4

3 回答 3

4

最好的办法是完全跳过匹配字符串的开头和结尾的尝试。如果您使用该方法,则必须这样做,matches()但如果您使用该方法,则不必这样做find()。这可能就是你想要的。

Pattern p = Pattern.compile("<b>\\s*([^<]*)\\s*<\\/b>");
Matcher m = p.matcher("some <b>text</b>");
m.find();

您可以使用start()andend()来查找包含匹配项的源字符串中的索引。您可以使用在匹配项内group()查找()捕获的内容(即粗体标记内的文本。

以我的经验,使用正则表达式来处理 HTML 是非常脆弱的,并且只在最微不足道的情况下工作得很好。改用成熟的 XML 解析器可能会更好,但如果这是其中一种微不足道的情况,那就试试吧。

原始答案:这是我的原始答案,分享为什么 a.*在比赛开始时表现如此糟糕。

在前面使用的问题.*是它会在你的比赛中导致很多回溯。例如,考虑以下情况:

Pattern p = Pattern.compile("(.*)ab(.*)");
Matcher m = p.matcher("aaabaaa");
m.matches();

比赛将这样进行:

  1. 匹配器将尝试将整个字符串“aaabaaa”吸进第一个.*,但随后尝试匹配a并失败。
  2. 匹配器将备份并匹配“aaabaa”,然后尝试匹配a并成功,但尝试匹配b并失败。
  3. 匹配器将备份并匹配“aaaba”,然后尝试匹配a并成功,但尝试匹配b并失败。
  4. 匹配器将备份并匹配“aaab”,然后尝试匹配a并成功,但尝试匹配b并失败。
  5. 匹配器将备份并匹配“aaa”,然后尝试匹配a并失败。
  6. 匹配器将备份并匹配“aa”,然后尝试匹配a并成功,尝试b并成功,然后将“aaa”匹配到 final .*。成功。

您希望尽可能避免在模式匹配开始时进行非常广泛的匹配。在不了解您的实际问题的情况下,很难提出更好的建议。

更新: Anirudha 建议使用(.*?)ab(.*)作为一种可能的解决方法来避免回溯。这会在一定程度上缩短回溯,但代价是每次尝试都尝试应用下一个匹配。所以现在,考虑以下几点:

Pattern p = Pattern.compile("(.*?)ab(.*)");
Matcher m = p.matcher("aaabaaa");
m.matches();

它将像这样进行:

  1. 匹配器将尝试不匹配任何内容,“”,进入第一个.*?,尝试匹配a并成功,但未能匹配b
  2. 匹配器将尝试将第一个字母“a”匹配到第一个.*?,尝试匹配a并成功,但匹配失败b
  3. 匹配器将尝试将前两个字母 "aa" 匹配到第一个.*?,尝试匹配a并成功,尝试匹配b并成功,然后将其余字母吞入.*"aaa"。成功。

这次没有任何回溯,但对于 内的每一次前进,我们仍然有一个更复杂的匹配过程.*?。这可能是特定匹配的性能提升,或者如果向前迭代匹配的速度较慢,则可能会造成损失。

这也改变了比赛的进行方式。匹配是贪婪的,并试图在更保守.*的地方尽可能多地匹配。.*?

例如,字符串“aaabaaabaaa”。

第一个模式(.*)ab(.*)将匹配“aaabaa”到第一个捕获和“aaa”到第二个。

第二个模式(.*?)ab(.*)将匹配“aa”到第一个捕获和“aaabaaa”到第二个。

于 2012-09-10T17:08:40.953 回答
3

而不是这样做"(.*)someRegex(.*)",为什么不只是在“someRegex”上拆分字符串并从结果数组中获取部分?这将为您提供相同的结果,但更快更简单。如果需要,Java 支持通过正则表达式拆分 - http://www.regular-expressions.info/java.html

于 2012-09-10T17:12:35.500 回答
1

.匹配每个字符

而不是尝试通过使用类似or.的类来限制您的搜索。\w\s

但我不保证它会运行得很快。

这完全取决于您匹配的文本数量!

于 2012-09-10T16:47:58.677 回答