【问题标题】:Regex Optimization for large lists大型列表的正则表达式优化
【发布时间】:2014-05-22 00:09:14
【问题描述】:

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

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

提前致谢

【问题讨论】:

    标签: java regex optimization


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      代替

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

      你可以使用

      s.contains(s2)
      

      s.indexOf(s2) > -1
      

      我测试了两者,每个都比 matches 快​​大约 35 倍。

      【讨论】:

        【解决方案3】:

        我认为您不应该为此使用 regex:我相信查看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");
                }
            }
        }
        

        【讨论】:

        • 这是您忘记尝试最简单解决方案的日子之一
        【解决方案4】:

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

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


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

        【讨论】:

          猜你喜欢
          • 2012-01-30
          • 1970-01-01
          • 1970-01-01
          • 2017-03-17
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多