大型列表的正则表达式优化
我正在比较两个字符串列表以找到可能的匹配。 例:
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)
,因为你没有似乎需要得到的索引。
无论如何,重用匹配器的这个概念是非常宝贵的。