StringBuilder를 사용하여 문자열의 모든 항목을 교체 하시겠습니까?


79

내가 뭔가를 놓치고 있거나 StringBuilder에 일반 String 클래스가 수행하는 동일한 "문자열 A의 모든 발생을 문자열 B로 교체"기능이 부족합니까? StringBuilder 교체 기능은 완전히 동일하지 않습니다. 일반 String 클래스를 사용하여 여러 문자열을 생성하지 않고 더 효율적으로이를 수행 할 수있는 방법이 있습니까?


download.oracle.com/javase/1.5.0/docs/api/java/lang/… 뭔가 빠졌는지 모르겠지만 그 기능이 존재하지 않는 것 같습니다.
meteoritepanama

2
String.replaceAll정규식이 있는 것 ? StringBuilder와 사이를 변환하는 오버 헤드에 대해 걱정하지 않습니다 String.
Tom Hawtin-tackline

답변:


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
경우에 경우주의 fromto다른 길이가이 솔루션은 각각의 교체에 꼬리를 버퍼로 이동합니다. 이것은 교체가 많이 발생하는 긴 버퍼의 경우 매우 비효율적 일 수 있습니다. Ron Romero의 답변에는 이러한 단점이 없지만 단일 정규식 검색이 포함됩니다. 더 빠른 것은 유스 케이스에 달려 있다고 생각합니다.
Vadzim

루프는 동안 필요하지 않습니다 :builder = builder.replace(builder.indexOf(from), builder.indexOf(from) + from.length(), to);
아미타 로이

1
@AmitabhaRoy : 질문에 명시된 모든 항목이 아니라 한 번의 항목 을 대체 합니다.
Jon Skeet

34

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

이것이 바로 제가 찾던 것입니다. Tnx!
dierre 2015

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

그 쪽이 맞는 거 같아요. 내가 뭘했는지 확인해야 겠어.
Adam Gent

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에서 아파치 코 몬즈 랭은 교체 할 수 있습니다 :

public StrBuilder replaceAll(String searchStr, String replaceStr)

* 정규식이 아닌 간단한 문자열을받습니다.


1
이제 더 이상 사용되지 않습니다.
afxentios

1
org.apache.commons.text.StringSubstitutor는 더 이상 사용되지 않는 이러한 유형의 작업을위한 훌륭한 라이브러리입니다. 그러나 StringBuilder가 아닌 Strings에서 작동합니다.
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

3

예. 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
질문은 String 클래스가 아닌 StringBuilder 클래스의 replaceAll에 관한 것입니다.
das Keks

질문은 StringBuilder 클래스를 사용하는 replaceAll ()에 관한 것입니다.
Sachin Sridhar


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

교체에 toReplace가 포함되어 있으면 무한 루프가되지 않습니까?
abhilash

1

다음은 StringBuilder에서 전달 된 내용을 수정하는 replaceAll입니다. 새 문자열을 만드는 대신 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);
    }
}

이 작업을 수행하는 코드가 얼마나 간단한 지 충격을 받았습니다 (어떤 이유로 Matcher를 사용하는 동안 StringBuilder를 변경하면 그룹 시작 / 종료가 발생한다고 생각했지만 그렇지 않습니다).

패턴이 이미 컴파일되어 있고 새 문자열을 만들지 않았지만 벤치마킹을 수행하지 않았기 때문에 이것은 다른 정규식 답변보다 빠를 것입니다.


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 ( ";", "/"); String 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();
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.