Заменить все вхождения строки с помощью StringBuilder?

Я что-то упускаю, или у StringBuilder нет такой же "замены всех вхождений строки A со строкой B", что и обычный класс String? Функция замены StringBuilder не совсем то же самое. Есть ли способ сделать это более эффективно, не генерируя несколько строк, используя обычный класс String?

Ответ 1

Ну, вы можете написать цикл:

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);
    }
}

Обратите внимание, что в некоторых случаях быстрее использовать lastIndexOf, работая со спины. Я подозреваю, что случай, если вы заменяете длинную строку коротким - поэтому, когда вы дойдете до начала, любые замены имеют меньше, чем копировать. В любом случае, это должно дать вам отправную точку.

Ответ 2

Вы можете использовать Pattern/Matcher. Из Matcher javadocs:

 Pattern p = Pattern.compile("cat");
 Matcher m = p.matcher("one cat two cats in the yard");
 StringBuffer sb = new StringBuffer();
 while (m.find()) {
     m.appendReplacement(sb, "dog");
 }
 m.appendTail(sb);
 System.out.println(sb.toString());

Ответ 3

Посмотрите на метод JavaDoc replaceAll класса String:

Заменяет каждую подстроку этой строки, которая соответствует данному регулярному выражение с данной заменой. Вызов этого метода формы str.replaceAll(regex, repl) дает точно такой же результат как выражение

java.util.regex.Pattern.compile(регулярное выражение).matcher(ул).replaceAll(REPL)

Как вы можете видеть, вы можете использовать Шаблон и Матчи.

Ответ 5

@Adam: Я думаю, что в вашем фрагменте кода вы должны отслеживать начальную позицию для m.find(), потому что замена строки может изменить смещение после последнего совпадающего символа.

public static void replaceAll(StringBuilder sb, Pattern pattern, String replacement) {
    Matcher m = pattern.matcher(sb);
    int start = 0;
    while (m.find(start)) {
        sb.replace(m.start(), m.end(), replacement);
        start = m.start() + replacement.length();
    }
}

Ответ 6

Даже простая использует сама функция String ReplaceAll. Вы можете записать его как

StringBuilder sb = new StringBuilder("Hi there, are you there?")
System.out.println(Pattern.compile("there").matcher(sb).replaceAll("niru"));

Ответ 7

java.util.regex.Pattern.matcher(CharSequence s) может использовать StringBuilder в качестве аргумента, чтобы вы могли находить и заменять каждый появление вашего шаблона с использованием start() и end() без вызова builder.toString()

Ответ 8

Используйте следующее:

/**
* Utility method to replace the string from StringBuilder.
* @param sb          the StringBuilder object.
* @param toReplace   the String that should be replaced.
* @param replacement the String that has to be replaced by.
* 
*/
public static void replaceString(StringBuilder sb,
                                 String toReplace,
                                 String replacement) {      
    int index = -1;
    while ((index = sb.lastIndexOf(toReplace)) != -1) {
        sb.replace(index, index + toReplace.length(), replacement);
    }
}

Ответ 9

Вот на месте replaceAll, который изменит переданный в StringBuilder. Я думал, что я опубликую это, поскольку я искал сделать replaceAll, создав новую строку.

public static void replaceAll(StringBuilder sb, Pattern pattern, String replacement) {
    Matcher m = pattern.matcher(sb);
    while(m.find()) {
        sb.replace(m.start(), m.end(), replacement);
    }
}

Я был шокирован тем, насколько простым был код, чтобы сделать это (по какой-то причине я думал, что изменение StringBuilder при использовании совпадения будет включать начало/конец группы, но это не так).

Это, вероятно, быстрее, чем другие ответы в регулярном выражении, потому что шаблон уже скомпилирован, и вы не создаете новую строку, но я не делал никаких бенчмаркинга.

Ответ 10

Как создать метод и String.replaceAll сделать это для вас:

public static void replaceAll(StringBuilder sb, String regex, String replacement)
{
    String aux = sb.toString();
    aux = aux.replaceAll(regex, replacement);
    sb.setLength(0);
    sb.append(aux);     
}

Ответ 11

public static String replaceCharsNew(String replaceStr,Map<String,String> replaceStrMap){
        StringBuilder replaceStrBuilder = new StringBuilder(replaceStr);
        Set<String> keys=replaceStrMap.keySet();
        for(String invalidChar:keys){
            int index = -1;
            while((index=replaceStrBuilder.indexOf(invalidChar,index)) !=-1){
                replaceStrBuilder.replace(index,index+invalidChar.length(),replaceStrMap.get(invalidChar));
            }
        }
        return replaceStrBuilder.toString();
    }

Ответ 12

Я нашел этот метод: Matcher.replaceAll (замена строки); В java.util.regex.Matcher.java вы можете увидеть больше:

 /**
 * Replaces every subsequence of the input sequence that matches the
 * pattern with the given replacement string.
 *
 * <p> This method first resets this matcher.  It then scans the input
 * sequence looking for matches of the pattern.  Characters that are not
 * part of any match are appended directly to the result string; each match
 * is replaced in the result by the replacement string.  The replacement
 * string may contain references to captured subsequences as in the {@link
 * #appendReplacement appendReplacement} method.
 *
 * <p> Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in
 * the replacement string may cause the results to be different than if it
 * were being treated as a literal replacement string. Dollar signs may be
 * treated as references to captured subsequences as described above, and
 * backslashes are used to escape literal characters in the replacement
 * string.
 *
 * <p> Given the regular expression <tt>a*b</tt>, the input
 * <tt>"aabfooaabfooabfoob"</tt>, and the replacement string
 * <tt>"-"</tt>, an invocation of this method on a matcher for that
 * expression would yield the string <tt>"-foo-foo-foo-"</tt>.
 *
 * <p> Invoking this method changes this matcher state.  If the matcher
 * is to be used in further matching operations then it should first be
 * reset.  </p>
 *
 * @param  replacement
 *         The replacement string
 *
 * @return  The string constructed by replacing each matching subsequence
 *          by the replacement string, substituting captured subsequences
 *          as needed
 */
public String replaceAll(String replacement) {
    reset();
    StringBuffer buffer = new StringBuffer(input.length());
    while (find()) {
        appendReplacement(buffer, replacement);
    }
    return appendTail(buffer).toString();
}

Ответ 13

Да. Использовать String.replaceAll() очень просто:

package com.test;

public class Replace {

    public static void main(String[] args) {
        String input = "Hello World";
        input = input.replaceAll("o", "0");
        System.out.println(input);
    }
}

Выход:

Hell0 W0rld

Если вы действительно хотите использовать вместо этого StringBuilder.replace(int start, int end, String str) то здесь вы идете:

public static void main(String args[]) {
    StringBuilder sb = new StringBuilder("This is a new StringBuilder");

    System.out.println("Before: " + sb);

    String from = "new";
    String to = "replaced";
    sb = sb.replace(sb.indexOf(from), sb.indexOf(from) + from.length(), to);

    System.out.println("After: " + sb);
}

Выход:

Before: This is a new StringBuilder
After: This is a replaced StringBuilder