2010-08-12 14 views
61

¿Me falta algo, o StringBuilder no tiene la misma función "reemplazar todas las apariciones de una cadena A con la secuencia B" que la clase String normal? La función de reemplazo StringBuilder no es lo mismo. ¿Hay alguna forma de hacerlo de manera más eficiente sin generar múltiples cadenas utilizando la clase String normal?Reemplazar todas las ocurrencias de una Cadena usando StringBuilder?

+0

http://download.oracle.com/javase/1.5.0/docs/api/java /lang/StringBuilder.html No sé si me falta algo, pero esa función no parece existir. – garsh0p

+0

¿Qué te hace pensar que la asignación de objetos es una forma menos eficiente de hacerlo? Dependiendo de la cantidad de caracteres que se deben copiar con cada paso de reemplazo "en el lugar", podría funcionar mejor que la operación in situ. – Dirk

+1

'String.replaceAll' la cosa con * regexs *? No me preocuparía la sobrecarga de convertir entre 'StringBuilder' y' String'. –

Respuesta

67

Bueno, se puede escribir un bucle:

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

Tenga en cuenta que en algunos casos puede ser más rápido usar lastIndexOf, trabajando desde la parte posterior. Sospecho que ese es el caso si reemplazas una cadena larga por una corta, por lo que cuando llegas al inicio, cualquier reemplazo tiene menos para copiar. De todos modos, esto debería darte un punto de partida.

+1

Tenga en cuenta que en caso de que 'from' y' to' tengan diferentes longitudes, esta solución movería la cola del buffer en cada reemplazo. Esto puede ser bastante ineficaz para un buffer largo con muchas ocurrencias de reemplazo. La respuesta de Ron Romero no tiene este inconveniente, pero implica la búsqueda única de expresiones regulares. Lo que sería más rápido depende del caso de uso, supongo. – Vadzim

31

usted podría utilizar Pattern/Matcher. De los javadocs Matcher:

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

esto es exactamente lo que estaba buscando. Tnx! – dierre

+5

Esto es casi lo mismo que Matcher # replaceAll(). – Shannon

+0

Esto funciona para "perro" pero es insuficiente en el caso _general_ porque la cadena de reemplazo tiene caracteres especiales. Si tiene la intención de utilizar referencias retros en los valores de reemplazo, entonces necesita escapar de todas las demás barras invertidas y de '$'. Si no necesita hacer referencia alguna a la cadena coincidente, puede simplemente ejecutar el texto de reemplazo a través de 'Matcher.quoteReplacement (...)'. Por lo tanto, 'm.appendReplacement (sb, Matcher.quoteReplacement (someText));' – AndrewF

11

Mira JavaDoc de replaceAll método de cadena clase:

reemplaza cada subcadena de esta cadena que coincide con la dada expresión regular con el reemplazo dado. Una invocación de este método de la forma str.replaceAll (expresiones regulares, repl) produce exactamente el mismo resultado como la expresión

java.util.regex.Pattern.compile (regex) .matcher (str) .ReplaceAll (sust)

Como se puede ver se puede utilizar patrón y Matcher de hacer eso.

2

Usar la siguiente:

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

una Incluso simple es utilizar la cadena ReplaceAll función en sí. Puede escribirlo como

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

Aquí hay un in situ replaceAll que modificará el pasado en StringBuilder. Pensé que publicaría esto porque quería reemplazar todo con la creación de un nuevo String.

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

Me sorprendió lo fácil el código para hacer esto era (por alguna razón pensé cambiar el StringBuilder durante el uso de la matcher arrojaría del grupo de inicio/final, pero no lo hace).

Esto es probablemente más rápido que las otras respuestas de expresiones regulares porque el patrón ya está compilado y no está creando un nuevo String, pero no hice ningún benchmarking.

9

@ Adam: Creo que en el fragmento de código debe hacer un seguimiento de la posición de inicio para m.find() porque el reemplazo de cadena puede cambiar el desplazamiento después del último carácter coincidente.

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

Creo que tienes razón. Tendré que verificar con qué terminé. –

+1

El código más eficiente de la memoria. Felicidades! –

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

Realmente debería agregar alguna explicación sobre por qué debería funcionar este código; también puede agregar comentarios en el código en sí; en su forma actual, no proporciona ninguna explicación que pueda ayudar al resto de la comunidad a comprender lo que le hizo resolver/responder la pregunta. – ishmaelMakitla

+0

Tuve la siguiente situación de que necesito reemplazar varios caracteres no válidos con algunos caracteres. Yo sólo pellizcado poco de código anterior y quería publicarlo @JUnitTest public void testReplaceCharsNew() { \t Map mapa = new HashMap (); \t map.put (",", "/"); \t map.put (".", ""); \t map.put (";", "/"); \t Cadena s = Utils.replaceCharsNew ("prueba; Reemplazar, Caracteres, Nuevo.", Mapa); \t assertEquals ("test/Replace/Chars/New", s); } – ramesh

1

¿Qué hay de crear un método y dejar String.replaceAll lo haga por usted:

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