Java字符串解析:正则表达式与字符串方法哪个更快?

9

我面临一个两难的境地。 我正在解析一个字符串,可以选择

s.matches(regex)

或者我可以做。
s.startsWith(..) && s.endsWith(..)

正如您已经意识到的那样,这不是一个复杂的正则表达式,两种情况都可以工作。 思路是,字符串可能非常长(数百个字符),因此我希望最大化效率。 哪种方法适用于问题并更好?


3
正则表达式由于需要编译,所以速度较慢。 - G.S
8
每当我看到像“什么更快?”这样的问题时,我总是想,“那就基准测试一下,自己试试就知道了”。 - HamZa
1
你可以在大约5分钟内编写基准测试。 - tom
请记得缓存您的正则表达式。 - Scary Wombat
2
为什么不计时执行两者并告诉我们时间? - Bohemian
显示剩余2条评论
3个回答

9

这里有一个相当粗略的基准测试,可供参考。将其调整到您的用例以获得更相关的结果。

简短总结

  • startsWith()endsWith()速度更快

详细结果

运行100万次后的结果:

- 未编译的模式:        1091 毫秒
- 已编译的模式:         745 毫秒
- startsWith() / endsWith(): 24 毫秒
public class TestRegex {

    String regex = "^start.*end$";
    Pattern p = Pattern.compile(regex);
    
    String start = "start";
    String end = "end";
    String search = start + "fewbjlhfgljghfadsjhfdsaglfdhjgahfgfjkhgfdkhjsagafdskghjafdkhjgfadskhjgfdsakhjgfdaskhjgafdskjhgafdsjhkgfads" + end;
    
    int runs = 1000000;

    @Test
    public final void test() {
        // Init run
        for (int i = 0; i < runs; i++) {
            search.matches(regex);
        }
        for (int i = 0; i < runs; i++) {
            p.matcher(search).matches();
        }
        for (int i = 0; i < runs; i++) {
            search.startsWith(start);
            search.endsWith(end);
        }


        // Timed run
        Stopwatch s = Stopwatch.createStarted();
        for (int i = 0; i < runs; i++) {
            search.matches(regex);
        }
        System.out.println(s.elapsed(TimeUnit.MILLISECONDS));
        s.reset();
        
        s.start();
        for (int i = 0; i < runs; i++) {
            p.matcher(search).matches();
        }
        System.out.println(s.elapsed(TimeUnit.MILLISECONDS));
        s.reset();
        
        s.start();
        for (int i = 0; i < runs; i++) {
            search.startsWith(start);
            search.endsWith(end);
        }
        System.out.println(s.elapsed(TimeUnit.MILLISECONDS));
    }

}

3
JIT将使用高度优化的汇编代码替换某些字符串方法;有时,它们可以用单个CPU指令替换。 - Aaron Digulla

5
请注意,如果期望在结束处的字符串是起始字符串的后缀,则两种方法可能报告不同的结果:
^start.*art$

无法匹配。
"start"

当……的时候
"start".startsWith("start") && "start".endsWith("art")

将会是真的。


2

实际上,即使是对于小字符串,它们之间的差异也是存在且明显的。使用模式的编译版本可以提高一些性能,但毫无疑问,在匹配容易的情况下,这是最糟糕的选择。

感谢大家。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接