速度优化java字符串包含的正则表达式与正则表达式匹配



如何提供最佳性能(速度)来检查句子是否包含任何关键字1、关键字2、关键字等。

以下是我的选择:

  1. 使用字符串容器:if(string.contains(item1)||string.contains(item2)||string.contains(item3))
  2. 或者在上面的if-or-or-or失去控制之前,为选项#1构建一个for循环
  3. 使用正则表达式
  4. 另一个选择是使用Java 8 Streaming API,这目前对我来说是不可用的。客户端使用Java 7

首先,每个答案都应该在生产条件下进行测试。当性能成为问题时,RAM和缓存大小、总线速度等都会发挥作用,使事情难以预测。另一个问题是这个代码会运行多少次——JVM最初会运行它的解释版本,只有在代码执行了足够的次数后,才会用编译的(更快的)版本取代它。

话虽如此,这里有一些提示:

  • 如果您有很多关键字,请考虑并行化任务。使用执行器或并行流。这只适用于大约100多个关键字,并且对于少量关键字,会使代码速度变慢
  • 如果关键词使用频率足够高,请尝试使用某些算法来搜索所有关键词,例如使用前缀树(也称为trie)。请注意,这些结构可能会导致内存使用效率低下,因为节点对象可能分散在内存中,从而在遍历时导致缓存未命中。这就是为什么ArrayList在实践中比LinkedList更快,尽管它们在理论上具有相似的特性
  • 尝试切换到字节数组(即使用String.getBytes),然后使用Arrays类的方法查找每个单词。这具有内存局部性的优点。请注意,Unicode在这里可能很棘手,因此您可能需要规范化首先

但最重要的是,测试。只要确保你正确地进行了微观基准测试。

我建议您使用regexp,因为它非常简单且功能强大

import java.util.regex.Matcher;
import java.util.regex.Pattern;
final String regex = "STRING1|STRING2|STRING3";
final String string = "xxxSTRING1xxxSTRING2xxx";
final Pattern pattern = Pattern.compile(regex);
final Matcher matcher = pattern.matcher(string);
while (matcher.find()) {
System.out.println("Full match: " + matcher.group(0));
for (int i = 1; i <= matcher.groupCount(); i++) {
System.out.println("Group " + i + ": " + matcher.group(i));
}
}

STDOUT:

Full match: STRING1
Full match: STRING2

在线IDE中的演示:此处

最新更新