如何从另一个String中有效地删除String的所有实例?

时间:2015-02-20 15:49:29

标签: java string performance replaceall string-utils

我正在解决的问题是将所有字符串替换为另一个字符串。

我使用String.replaceAll在codingbat.com上相当容易地解决了这个问题,直到第一个String不再包含其他String为止。

但是,我不喜欢这种方法,因为它很慢。我试图在这个网站上搜索更有效的方法,并遇到了这些问题:

Fastest way to perform a lot of strings replace in Java

String.replaceAll is considerably slower than doing the job yourself

他们使用StringUtils和Patterns解决了这个问题。我仍然认为这些方法太慢了!

当我编写像这样的问题时,我喜欢用Java在两秒钟内获得运行时。我用一个1,000,000个字符的字符串来测试它。 String.replaceAll超过两秒,其他两种方法也是如此。

有没有人有这个问题的快速解决方案?谢谢!

编辑:不幸的是,我收到的答案仍然运行得太慢。是的,我的意思是创建一个新的String,而不是更改旧的String,抱歉这个错误。

我不确定它是如何工作的,但我认为循环每个字符并检查可能有效。算法的东西。

5 个答案:

答案 0 :(得分:1)

字符串是不可变的,因此您无法从中删除内容。这意味着您需要创建一个没有要删除的东西的新String。当您使用String.replace时,它几乎就是它所做的:它创建一个新的String。

谨防String.replaceAll,因为它使用的是每次调用时都会编译的正则表达式(所以永远不要在长循环中使用它)。这可能是你的问题。

如果需要使用正则表达式,请使用Pattern类编译正则表达式并重用该实例,为您处理的每个字符串创建一个新的Matcher。如果你不重用你的Pattern实例,那就会很慢。

如果您不需要正则表达式,StringUtils有一个不依赖正则表达式的replaceEach()。

如果您正在处理大字符串。您可能希望以流式方式执行操作并循环遍历字符并将字符复制到StringBuilder。

或者,您可以使用正则表达式在String中搜索特定模式并循环搜索它找到的匹配项,并为每个匹配项添加从上一个匹配到当前匹配的所有内容到StringBuilder。

答案 1 :(得分:1)

问题是你的字符串很大,你只想移动/复制一次,所有使用多次调用替换的解决方案仍然会做大量不必要的工作。

您真正想要使用的是Apache StringUtils.replaceEachRepeatedly,因为该方法只处理搜索多个字符串,而只构建一个结果字符串。

答案 2 :(得分:0)

除了每个方法(替换,StringUtils或Patterns,...)之外,只有一个Thread工作。

如果您可以将该线程完成的工作拆分为两个或更多,例如每个Thread在字符串中的特定位置运行到另一个,您将能够快速解决。

棘手的部分是分割工作然后将它们连接在一起。 这将取决于你如何读取字符串,例如,你在哪里写它。

问候,

答案 3 :(得分:0)

前段时间我遇到了同样的问题并且来到这篇文章:Replace all occurrences of a String using StringBuilder?

使用帖子中给出的实现:

public static void main(String[] args) {
    String from = "A really long string full of ands and ors";
    String replaceFrom = "and";
    String replaceTo = "or";

    long initTime = System.nanoTime();
    String result1 = from.replace(replaceFrom, replaceTo);
    System.out.println("Time1: " + (System.nanoTime() - initTime));

    System.out.println(result1);

    StringBuilder sb1 = new StringBuilder(from);
    initTime = System.nanoTime();
    replaceAll(sb1, replaceFrom, replaceTo);
    System.out.println("Time1: " + (System.nanoTime() - initTime));

    System.out.println(sb1.toString());
}

// From https://stackoverflow.com/questions/3472663/replace-all-occurences-of-a-string-using-stringbuilder
public static void replaceAll(StringBuilder builder, String from, String to) {
    int index = builder.indexOf(from);
    while (index != -1) {
        builder.replace(index, index + from.length(), to);
        index += to.length(); // Move to the end of the replacement
        index = builder.indexOf(from, index);
    }
}

对第二种解决方案更好性能的解释是它继承了StringBuilder,一个可变对象而不是String是一个不可变对象。有关更好的解释,请参阅Immutability of Strings in Java

此解决方案将同时使用StringBuffer和StringBuilder,但正如Difference between StringBuilder and StringBuffer中所述,StringBuffer已同步且StringBuilder未同步,因此如果您不需要同步,则最好使用StringBuilder。

答案 4 :(得分:0)

我刚试过这个,结果是:

  

100960923

     

197642683484

import java.util.Stack;
public class Test {   

public static String removeAll(final String stringToModify, final String stringToFindAndRemove) {
    if (stringToModify==null||stringToModify.length()==0) return new String(stringToModify);
    if (stringToFindAndRemove==null||stringToFindAndRemove.length()==0) return new String(stringToModify);
    if (stringToModify.length()<stringToFindAndRemove.length()) return new String(stringToModify);
    int lastChar = 0;
    int buffPos=0;
    Stack<Integer>stack = new Stack<Integer>();
    char[] chars = stringToModify.toCharArray();
    char[] ref = stringToFindAndRemove.toCharArray();
    char[] ret = new char[chars.length];        
    for (int a=0;a<chars.length;a++) {
        if (chars[a]==ref[buffPos]) {
            if (buffPos==ref.length-1) {
                buffPos=0;
                stack.pop();
            } else {
                if (buffPos==0) stack.push(lastChar);                   
                buffPos++;
            }
        } else {
            if (buffPos!=0) {
                for (int b=0;b<buffPos;b++) {
                    ret[lastChar]=ref[b];
                    lastChar++;
                }
                a--;
                buffPos = 0;
            }  else {
                ret[lastChar]=chars[a];
                lastChar++;                 
            }
        }                   
        if (stack.size()>0&&(lastChar-stack.peek()>=ref.length)) {
            while(stack.size()>0 && (lastChar-stack.peek()>=ref.length)) {
                int top = stack.pop();
                boolean f = true;                   
                for (int foo=0;foo<ref.length;foo++) {
                    if (ret[top+foo]!=ref[foo]) {
                        f=false;
                        break;
                    }
                }
                if (f) lastChar=top;                    
            }
        }           
    }
    if (buffPos!=0) {
        for (int b=0;b<buffPos;b++) {
            ret[lastChar]=ref[b];
            lastChar++;
        }
    }
    char[] out = new char[lastChar];
    System.arraycopy(ret,0,out,0,lastChar);
    return new String(out);
}

    public static void main(final String[] args) {        
        StringBuffer s = new StringBuffer();
        StringBuffer un = new StringBuffer();       
        for (int a=0;a<100000;a++) {
            s.append("s");
            un.append("un");
        }
        StringBuffer h = new StringBuffer(s);
        h.append(un);
        h.append("m");
        String huge = h.toString();
        String t = "sun";
        long startTime = System.nanoTime();             
        String rep = removeAll(huge,t);
        long endTime = System.nanoTime();
        long duration = (endTime - startTime);
        //System.out.println(rep);
        System.out.println(duration);
        startTime = System.nanoTime();      
        rep = new String(huge);
        int pos = rep.indexOf(t);
        while (pos!=-1) {
            rep = rep.replaceAll(t,"");
            pos = rep.indexOf(t);
        }       
        endTime = System.nanoTime();
        duration = (endTime - startTime);
        //System.out.println(rep);
        System.out.println(duration);
    }
}

我有兴趣看一下这台机器有多快。因为我的老板认为我的机器足够快! :)