使用积极的后视或后引用是否更有效?

Mic*_*ael 5 java regex

使用我刚才回答的问题代码作为例子

从字符串开始

30-Nov-2012 30-Nov-2012 United Kingdom, 31-Oct-2012 31-Oct-2012 United
Arab Emirates, 29-Oct-2012 31-Oct-2012 India 
Run Code Online (Sandbox Code Playgroud)

如果我们想要在每个四位数字之后替换空格@,以便最终得到这样的结果,那该怎么办:

30-Nov-2012@30-Nov-2012@United Kingdom, 31-Oct-2012@31-Oct-2012@United
Arab Emirates, 29-Oct-2012@31-Oct-2012@India  
Run Code Online (Sandbox Code Playgroud)

使用反向引用而不是积极的外观(如果有的话)效率更高?

反向引用:

inputString.replaceAll("(\\d{4})\\s", "$1@");
Run Code Online (Sandbox Code Playgroud)

积极的观察:

inputString.replaceAll("(?<=\\d{4})\\s", "@");
Run Code Online (Sandbox Code Playgroud)

das*_*ght 5

在第一个示例中没有反向引用,它是对输出中编号的捕获组的引用.

两种情况下的搜索效率都是一样的; 区别仅在于捕获的内容.因此,性能的总体差异将归结为替换字符串内容的差异:在第一种情况下,两个字符串组合形成替换,而在第二种情况下,仅使用一个字符串.从理论上讲,第一种情况应该需要稍微多一点的工作,但实际上差异不大可能是显而易见的.

编辑:正如acheong87的测试所示,使用正向前瞻在Java中效率将降低近50%.此外,这种低效率并不似乎是针对Java(尽管它在Java的幅度是巨大的:C#程序相当于一个acheong87显示约24%的单下在Windows下放缓,约21%).

我想这个练习的主要教训是,表达式的理论近似等价并不能保证实际中的等效时间:没有替代实际实现的概要分析.

  • @Michael这个教程有点误导:当您在同一个表达式中引用捕获组时会发生后向引用,例如`"([AZ]) - \\ 1"`.这将匹配`AA`,`BB`,`CC`等; 在这种情况下,`\\ 1`是后引用,因为它将"返回"引用到先前已捕获的组.当你在替换字符串中使用`$ 1`语法时,它只是一种引用捕获组的方法. (2认同)

And*_*ong 5

我承认我的测试方法很粗糙,可能有缺陷(而且我不懂Java,只学习写这个答案),但我的初步证据证明与@ dasblinkenlight的答案相反.我运行了以下代码:

import java.util.*;
import java.lang.*;

class Main
{
    private static void test (String regex, String replace, int repetitions)
    {
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < repetitions; i++)
        {
            String str = "30-Nov-2012 United Kingdom, 31-Oct-2012 31-Oct-2012 United Arab Emirates, 29-Oct-2012 31-Oct-2012 India, ";
            str.replaceAll(regex, replace);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("Execution time: " + Long.toString(endTime - startTime));
    }

    public static void main (String[] args) throws java.lang.Exception
    {
        test("(\\d{4})\\s", "$1@", 10000);
        test("(?<=\\d{4})\\s", "@", 10000);
        test("(\\d{4})\\s", "$1@", 10000);
        test("(?<=\\d{4})\\s", "@", 10000);
        test("(\\d{4})\\s", "$1@", 10000);
        test("(?<=\\d{4})\\s", "@", 10000);
        test("(\\d{4})\\s", "$1@", 10000);
        test("(?<=\\d{4})\\s", "@", 10000);
    }
}
Run Code Online (Sandbox Code Playgroud)

...这里,http://ideone.com/WkHLMN,输出结果为:

Execution time: 164
Execution time: 140
Execution time: 96
Execution time: 135
Execution time: 95
Execution time: 133
Execution time: 94
Execution time: 130
Run Code Online (Sandbox Code Playgroud)

忽略第一组案例作为与初始化有关的异常值,其余案例似乎表明后一个表达式,使用正向后看断言,可能会多做50%的工作量!我怀疑情况可能就是这种情况,因为传递感兴趣的字符,反向引用需要返回检查断言是否为真.

  • 通过实际测量找出事情.我赞成! (2认同)