java正则效率_译:Java 中的正则表达式性能概述

译者:Darren Luo

1. 概述

在本快速教程中,我们将展示模式匹配引擎是如何工作的。我们还将介绍在 Java 中优化正则表达式的不同方式。

有关正则表达式的的使用介绍,请参阅此文。

2. 模式匹配引擎

java.util.regex 包使用了一种叫做 Nondeterministic Finite Automaton(NFA)(不确定性有穷自动机)的模式匹配引擎。它被认为是不确定的是因为在对给定字符串尝试匹配正则表达式时,输入的每个字符可能针对正则表达式的不同部分进行多次检查。

在后台,上面提到的引擎使用回溯。这种通用算法尝试用尽所有可能性,知道它宣告失败。考虑下面的示例可以更好的理解 NFA:

"tra(vel|ce|de)m"

在输入字符串“travel”时,该引擎首先会查找“tra”并立即找到它。

在这之后,它将从第四个字符开始尝试匹配“vel”。这将匹配上,所以她将继续并尝试匹配”m“。

那将不能匹配,因此,它将回到第四个字符并搜索”ce“。这次将不再匹配,所以它将再次回到第四个位置并尝试匹配”de“。这个字符串耶不能匹配,因此它将返回输入字符串的第二个字符并尝试搜索另一个“tra”。

最后一次失败时,算法将返回失败。

在上面的简单例子里,在尝试将输入字符串和正则表达式匹配时,引擎必须多次回溯。因此,减少回溯次数时非常重要的。

3. 优化正则表达式的方法

3.1 避免重新编译

Java 中的正则表达式被编译为内部数据接口。这个编译时一个耗时的过程。

我们每次调用 String.matches(String regex) 方法时,制定的正则表达式都会重新编译。

if (input.matches(regexPattern)) {

// do something

}

我们可以看到,每次进行条件求值时,正则表达式将被编译。

要进行优化,只能首先编译模式,然后创建一个 Matcher 来查找值中的匹配:

Pattern pattern = Pattern.compile(regexPattern);

for(String value : values) {

Matcher matcher = pattern.matcher(value);

if (matcher.matches()) {

// do something

}

}

上述优化的替代方案时使用相同的 Matcher 示例及其 reset() 方法:

Pattern pattern = Pattern.compile(regexPattern);

Matcher matcher = pattern.matcher("");

for(String value : values) {

matcher.reset(value);

if (matcher.matches()) {

// do something

}

}

由于 Matcher 不是线程安全的情况,我们必须谨慎使用这种变体。在多线程场景中可能存在危险。

总而言之,无论哪种情况,我们都保证在任何时间点都只有一个 Matcher 用例,可以用 reset 来重用它。对于这个例子,重复使用预编译已经足够了。

3.2. 使用替换(Alternation)

正如上一节我们测试的那样,替换使用不当可能会对性能产生影响。最重要的是将选项放置最可能发生的前方,这样能更快的匹配。

此外,我们必须提取提取他们之间的共同模式。下面两个是不一样的:

(travel | trade | trace)

对比:

tra(vel | de | ce)

后一个更快,因为 NFA 将尝试匹配“tra”,如果没找到它,则不会尝试任何替代方案。

3.3. 捕获分组(Group)

每次我们捕获分组时,我们都会遭受一次小规模的惩罚。

如果我们需要在分组里捕获文本,我们应该考虑使用非捕获分组。请用“(?:M)”替代使用“(M)”。

总结

在这篇短文中,我们简要回顾了 NFA 的工作原理。然后,我们通过与扁我们的模式并重用 Matcher 来探索如何优化我们正则表达式的性能。

最后,我们指出我们在使用替换和分组的一些注意事项。

和往常一样,可以在 Github 上找到完整的源代码。

http://www.spring4all.com/article/1479

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值