2014-04-09 33 views
1

我正在比较两个字符串列表以查找可能的匹配项。例如:用于大型列表的正则表达式优化

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左右的字符串。这种比较需要很长的时间,并且希望看看是否有可能优化比较。测试2中的第一个1.5K项目需要大约10分钟的时间。所以完成比较至少需要30到40分钟。

在此先感谢

回答

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并享受速度。

0

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

在你的代码的顶部,这样做:

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

然后在你的循环,这样做:

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

但我会用@maaartinus这里同意,并说,根据您的要求,您根本不需要regex,而可以使用indexOf(s),或者甚至更好的contains(s),因为您似乎不需要生成的索引。

无论如何,这个重用匹配器的概念是无价的。

1

而不是

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

可以使用

s.contains(s2) 

s.indexOf(s2) > -1 

我测试的两种,各为约35倍比matches更快。