使用StringBuilder替换所有出现的String吗?


78

我是否缺少某些东西,或者StringBuilder是否缺少与普通String类相同的“用字符串B替换所有出现的字符串A”功能?StringBuilder的替换功能并不完全相同。有没有什么方法可以更有效地使用普通的String类生成多个String?


download.oracle.com/javase/1.5.0/docs/api/java/lang/… 我不知道我是否缺少某些东西,但是该功能似乎不存在。
meteoritepanama

2
String.replaceAll正则表达式的事情?我不会担心在StringBuilder和之间进行转换的开销String
汤姆·霍顿

Answers:


76

好了,您可以编写一个循环:

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,从背面开始使用可能会更快。我怀疑是这样,如果要用短字符串替换长字符串-因此,从一开始,任何替换副本的复制量都很少。无论如何,这应该给您一个起点。


1
注意,如果from和的to长度不同,此解决方案将在每次替换时移动缓冲区尾部。这对于发生很多替换的长缓冲区可能是非常无效的。罗恩·罗梅罗(Ron Romero)的答案没有这个缺点,但是涉及到单个正则表达式搜索。我猜想更快些取决于用例。
Vadzim 2013年

不需要While-Loop:builder = builder.replace(builder.indexOf(from), builder.indexOf(from) + from.length(), to);
Amitabha Roy

1
@AmitabhaRoy:那将取代一个事件,而不是问题中所述的所有事件。
乔恩·斯基特

34

您可以使用模式/匹配器。从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());

这正是我想要的。天哪!
dierre 2013年

5
这几乎与Matcher#replaceAll()相同。
香农

这适用于“ dog”,但在一般情况下是不够的,因为替换字符串具有特殊字符。如果打算在替换值中使用反引用,则需要转义所有其他反斜杠和$。如果您根本不需要引用匹配的字符串,则只需通过即可运行替换文本Matcher.quoteReplacement(...)。所以m.appendReplacement(sb, Matcher.quoteReplacement(someText));
AndrewF

14

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

我想你是对的。我将不得不检查最终结果。
亚当·根特

13

查看String类的replaceAll方法的JavaDoc :

用给定的替换项替换该字符串中与给定的正则表达式匹配的每个子字符串。以str.replaceAll(regex,repl)形式调用此方法,其结果与表达式完全相同

java.util.regex.Pattern.compile(regex).matcher(str).replaceAll(repl)

如您所见,您可以使用PatternMatcher来做到这一点。


11

这个类org.apache.commons.lang3.text.StrBuilder的Apache Commons Lang中允许更换:

public StrBuilder replaceAll(String searchStr, String replaceStr)

*它不接收正则表达式,而是一个简单的字符串。


1
现在已弃用。
afxentios '18

1
org.apache.commons.text.StringSubstitutor是一个很好的库,用于不推荐使用的此类工作。但是适用于Strings,而不适用于StringBuilder。
Ted Cahall,

您可以改用org.apache.commons.commons-text中的org.apache.commons.text.TextStringBuilder
ihebiheb

6

甚至很简单的一种就是使用String ReplaceAll函数本身。你可以写成

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

1
replaceAll方法返回String。因此它将在字符串池中生成一个实例。当要进行多个不同的替换时,这不是一种有效的方法。
AbhishekB


2

使用以下内容:

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

2

是。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

3
问题是关于StringBuilder类而不是String类中的replaceAll。
das Keks,

问题是关于使用StringBuilder类的replaceAll()。
萨钦·斯里达

1

这是一个就地replaceAll,它将修改在StringBuilder中传递的内容。我以为我打算在不创建新String的情况下执行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会引发组开始/结束,但事实并非如此)。

这可能比其他正则表达式的答案要快,因为该模式已经编译,并且您没有创建新的String,但是我没有进行任何基准测试。


0

如何创建方法并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);     
}

这是内存/分配的非常低效的用法。
afollestad

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

您实际上应该添加一些有关此代码为何起作用的解释-您还可以在代码本身中以当前形式添加注释-它没有提供任何解释,可以帮助社区的其他成员了解您要解决的问题/回答问题。
ishmaelMakitla

我有以下这种情况,我需要用一些字符替换多个无效字符。我只是对上面的代码做了些微调整,并想将其发布到@JUnitTest public void testReplaceCharsNew(){Map <String,String> map = new HashMap <String,String>(); map.put(“,”,“ /”); map.put(“。”,“”); map.put(“;”,“ /”); 字符串s = Utils.replaceCharsNew(“ test; Replace,Chars,New。”,map); assertEquals(“ test / Replace / Chars / New”,s); }
ramesh

0

我找到了这个方法:Matcher.replaceAll(String replacement); 在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();
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.