2010-10-01 12 views
5

Tengo una clase que está haciendo un montón de procesamiento de texto. Para cada cadena, que tiene entre 100 y> 2000 caracteres de longitud, estoy realizando 30 reemplazos de cadena diferentes.Java's String.replace() vs. String.replaceFirst() vs. homebrew

Ejemplo:

string modified; 
for(int i = 0; i < num_strings; i++){ 
modified = runReplacements(strs[i]); 
//do stuff 
} 

public runReplacements(String str){ 
    str = str.replace("foo","bar"); 
    str = str.replace("baz","beef"); 
    .... 
    return str; 
} 

'foo', 'baz', y todos los demás "blancos", sólo se espera que aparezcan una vez y son literales de cadena (sin necesidad de una expresión regular real).

Como se puede imaginar, estoy preocupado por el rendimiento :)

Ante esto,

  • replaceFirst() parece una mala opción, ya que no utilizará Pattern.LITERAL y hará procesamiento adicional que ISN' t requerido.

  • replace() parece una mala elección, ya que recorrerá toda la cadena en busca de múltiples instancias para ser reemplazados.

Además, dado que mis textos de reemplazo son los mismos cada vez, parece que tiene sentido para mí escribir mi propio código de otro modo String.replaceFirst() o String.replace() a estar haciendo un Pattern.compile cada vez en el fondo. Pensando que debería escribir mi propio código, este es mi pensamiento:

  • Realice una Pattern.compile()sola vez para cada sustitución literal deseada (sin necesidad de volver a compilar cada vez) (es decir, P1 - P30)

  • a continuación, haga lo siguiente para cada pX: p1.matcher(str).replaceFirst(Matcher.quoteReplacement("desiredReplacement"));

esta manera que abandonar el barco en la primera sustitución (en lugar de atravesar toda la cadena), y estoy usando literal frente a regex, y no estoy haciendo una nueva compilación en cada iteración.

Entonces, ¿cuál es el mejor rendimiento?

Respuesta

3

Entonces, ¿cuál es el mejor rendimiento?

¡Midalo! ;-)

ETA: Como una respuesta de dos palabras suena irrecusablemente sarcástica, lo elaboraré un poco. "Mídelo y cuéntanos ..." ya que puede haber una regla general sobre el rendimiento de los diversos enfoques que cites (todos buenos), pero no me doy cuenta. Y como mencionamos algunos de los comentarios sobre esta respuesta, aun así, los diferentes enfoques tienen una alta probabilidad de ser inundados por el entorno de la aplicación. Por lo tanto, mídalo in vivo y concéntrese en esto si es un problema real. (Y háganos saber cómo va ...)

+1

Maldita sea, pásamela. @jonathon, no tienes un problema de rendimiento hasta que sabes que tienes un problema de rendimiento. – dty

+2

y medirlo en el contexto de su aplicación haciendo lo que se supone que debe hacer, puede parecer mucho trabajo, pero podría perderse fácilmente en el ruido de las llamadas a cualquier tráfico de red. –

2

Primero, ejecute y perfile toda su aplicación con una simple coincidencia/reemplazo.Esto se puede demostrar que:

  • su aplicación ya funciona lo suficientemente rápido, o
  • su solicitud es pasar la mayor parte de su tiempo haciendo otra cosa, por lo que la optimización del partido/reemplazar el código no vale la pena.

Suponiendo que usted ha determinado que el fósforo/reemplazar es un cuello de botella, escribir una pequeña aplicación de la evaluación comparativa que le permite probar el rendimiento y la exactitud de sus algoritmos de candidatos en los datos de entrada representativos. También es una buena idea incluir datos de entrada de "mayúsculas y minúsculas" que puedan causar problemas; p.ej. para las sustituciones en su ejemplo, los datos de entrada que contienen la secuencia "bazoo" podrían ser un caso marginal. Por el lado del rendimiento, asegúrese de evitar las trampas de la micro-evaluación comparativa de Java; p.ej. Efectos de calentamiento de JVM.

A continuación, implemente algunas alternativas simples y pruébelas. ¿Es uno de ellos lo suficientemente bueno? ¡Hecho!

Además de sus ideas, puede probar con la concatenación de los términos de búsqueda en una sola expresión regular (por ejemplo, "(foo | Baz)"), utilice Matcher.find(int) encontrar cada vez que aparece, utilice un HashMap para buscar las cadenas de recambio y un StringBuilder para construir la cadena de salida desde subcadenas y reemplazos de cadenas de entrada. (OK, esto no es del todo trivial, y depende del manejo del Patrón/Matcher se alterna de manera eficiente ... lo cual no estoy seguro es el caso. Pero es por eso que debe comparar los candidatos cuidadosamente.)

En (IMO improbable) si una alternativa simple no lo corta, this wikipedia page tiene algunos contactos que pueden ayudarlo a implementar su propia combinación eficiente/sustituto.

0

¿No es frustrante cuando haces una pregunta y recibes un montón de consejos que te dicen que hagas un montón de trabajo y lo resuelves por ti mismo?

Digo use replaceAll();

(no tengo ni idea de si lo es, de hecho, el más eficiente, sólo que no quiero que se sienta como si perdido su dinero en esta pregunta y no tiene nada.)

[editar] PS . Después de eso, es posible que desee medirlo.

[editar 2] PPS. (y cuéntanos qué has encontrado)

Cuestiones relacionadas