Java中的正则表达速度

时间:2010-12-01 03:47:42

标签: java regex optimization

大量字符串的一些示例挂钟时间:

.split("[^a-zA-Z]"); // .44 seconds
.split("[^a-zA-Z]+"); // .47 seconds
.split("\\b+"); // 2 seconds

对戏剧性增加的任何解释?我可以想象在处理器中完成的[^ a-zA-Z]模式是一组四个比较操作,只有当它是真实情况时才会发生这四个比较操作。 \ b怎么样?任何人都有什么可以权衡的吗?

2 个答案:

答案 0 :(得分:4)

首先,分割一个或多个零宽度断言是没有意义的! Java的正则表达式并不是非常聪明 - 而且我是慈善事业 - 关于理智的优化。

其次,永远不要在Java中使用\b:它与\w混乱并且不同步。

有关此内容的更完整说明,尤其是如何使用Unicode,请参阅this answer

答案 1 :(得分:-1)

\b是零宽度断言,与[^A-Za-z]根本不同。因为\b是作为if / then实现的(请参阅下面的tchrist评论),所以检查每个字符串中的每个字母可能需要做更多的工作。此外,加号导致回溯,这将使该成本倍增。

此外,当您在单词边界上进行拆分时,与仅在[^a-zA-Z]+上拆分相比,您将在更多地方匹配。这将导致分配更多字符串,这也将花费更多时间。 要看到这一点,请尝试以下程序:

import java.lang.String;

class RegexDemo {
    private static void testSplit(String msg, String re) {
        String[] pieces = "the quick brown fox".split(re);
        System.out.println(msg);
        for (String s : pieces) {
            System.out.println(s);
        }
        System.out.println("----");
    }

    public static void main(String args[]) {
        testSplit("boundary:", "\\b+");
        testSplit("not alpha:", "[^A-Za-z]+");
    }
}

可能不相关,当您使用String.split()时,必须为每次使用编译正则表达式。 如果您将正则表达式预编译为模式,例如,

Pattern boundary = Pattern.compile("\\b+");

然后使用boundary.split(testString)进行拆分,您将节省为每个测试字符串编译正则表达式的成本。所以,可以想象编译" \ b +"比其他模式的编译慢,你可以在这里使用预编译的习惯用法进行测试,虽然这似乎不太可能是我的解释。

有关正则表达式性能的更多信息,请阅读Russ Cox http://swtch.com/~rsc/regexp/的这些文章并查看http://www.regular-expressions.info/