Заменить все вхождения строки, используя StringBuilder?

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

14 ответов

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

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, работая со спины. Я подозреваю, что это так, если вы заменяете длинную строку на короткую, поэтому, когда вы начинаете, любые замены копируются меньше. Во всяком случае, это должно дать вам отправную точку.

Вы можете использовать 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());

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

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

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

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

Как вы можете видеть, вы можете использовать Pattern и Matcher для этого.

Класс org.apache.commons.lang3.text.StrBuilder в http://Apache%20Commons%20Lang допускаются замены:

public StrBuilder replaceAll(String searchStr, String replaceStr)

* Это не получает регулярное выражение, а простая строка.

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

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

Да. Это очень просто в использовании 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

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

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

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

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

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 при использовании средства сравнения может вызвать начало / конец группы, но это не так).

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

Как насчет создания метода и пусть 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);     
}

Я нашел этот метод: 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's 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();
}
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();
    }

Котлин Метод

        fun replaceAllStringBuilder(
        builder: java.lang.StringBuilder,
        from: String,
        to: String
    ) {
        if (!builder.contains(from)||from.isNullOrEmpty()) return
        
            var index = builder.indexOf(from)
            while (index != -1) {
                builder.replace(index, index + from.length, to)
                index += to.length 
                index = builder.indexOf(from, index)
            }
        

    }
Другие вопросы по тегам