大型列表的正则表达式优化

我正在比较两个字符串列表以找到可能的匹配。 例:

public class Tester { public static void main(String[] args) { List test = new ArrayList(); List test2 = new ArrayList(); test.add("3H0875AAAA0012"); test.add("3H0875AABB0018"); test.add("3H0875AAAC0010"); test2.add("3H0875AA"); for(String s2: test2){ for (String s: test){ if (s.matches(".*" + s2 + ".*")){ System.out.println("Match"); } } } } } 

基本上对于test2每个字符串,我想看看test中是否有任何完全或部分包含test2字符串。 上面代码的输出应该是:

 Match Match Match 

但是,在我的实际情况中,我在测试中有大约225K个字符串,在test2中有大约5K个字符串。 这个比较需要太长的过程,并想看看是否有可能优化比较。 分析test2中的前1.5K项需要大约10分钟。 因此完成比较至少需要30到40分钟。

提前致谢

我认为你不应该使用正则表达式 :我相信查看String#contains (这里是它的javadoc条目的链接 )会在性能方面给你更好的结果;)

例如,您的代码可能是:

 for(final String s2: test2){ for (final String s: test){ if(s.contains(s2)) { System.out.println("Match"); } } } 

应该禁止使用像String.matches(String)这样的IMHO方法。 也许你需要一个正则表达式匹配,也许不是,但这里发生的是,你的字符串被一次又一次编译成一个正则表达式。

那么请自己Pattern.compile ,然后通过Pattern.compile将所有内容转换为正则表达式Pattern.compile用它们。


看着你的".*" + s2 + ".*" ,我敢打赌你根本不需要正则表达式。 只需使用String.contains并享受速度。

代替

 s.matches(".*" + s2 + ".*") 

您可以使用

 s.contains(s2) 

要么

 s.indexOf(s2) > -1 

我测试了两者,每个比matches快35倍。

在这种情况下,您绝对应该创建一个Matcher对象,并在每次循环迭代中使用该单个对象。 您当前正在每次循环迭代中创建一个新的匹配器(并编译一个新的Pattern )。

在代码的顶部,执行以下操作:

 //"": Unused to-search string, so the matcher object can be reused Matcher mtchr = Pattern.compile(".*" + s2 + ".*").matcher(""); 

然后在你的循环中,执行以下操作:

 if(mtchr.reset(s).matches()) { ... 

但是我同意@maaartinus这里,并说,根据你的要求,你根本不需要正则表达式,而是可以使用indexOf(s) ,甚至更好, contains(s) ,因为你没有似乎需要得到的索引。

无论如何,重用匹配器的这个概念是非常宝贵的。