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

时间:2014-04-09 02:11:05

标签: java regex optimization

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

public class Tester {

    public static void main(String[] args) {

        List<String> test = new ArrayList<String>();
        List<String> test2 = new ArrayList<String>();

        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分钟。

提前致谢

4 个答案:

答案 0 :(得分:3)

我认为你不应该使用正则表达式:我相信调查String#contains(这里是link to its javadoc entry)会给你更好的结果,在表现方面;)

例如,您的代码可能是:

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

答案 1 :(得分:1)

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

请自己帮个忙,然后通过Pattern.compile将所有内容转换为正则表达式并重复使用。


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

答案 2 :(得分:1)

而不是

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

你可以使用

s.contains(s2)

s.indexOf(s2) > -1

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

答案 3 :(得分:0)

在这种情况下,您绝对应该创建一个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),因为你似乎不需要得到的索引。

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