2011-09-21 14 views
10

Parte del código en el que estoy trabajando usa un montón de expresiones regulares para buscar algunos patrones simples de cadena (por ejemplo, patrones como "foo [0-9] {3,4} bar") Actualmente, utilizamos Java Patterns compilados estáticamente y luego llamamos al Pattern#matcher para verificar si una cadena contiene una coincidencia con el patrón (no necesito la coincidencia, solo un booleano que indica si hay una coincidencia). Esto está causando una notable cantidad de asignación de memoria que está afectando el rendimiento.Expresiones regulares simples de alto rendimiento de Java

¿Existe una mejor opción para la coincidencia de expresiones regulares de Java que sea más rápida o que al menos no asigne memoria cada vez que busque una cadena en un patrón?

+0

qué tal http://download.oracle.com/javase/1.4.2/docs/api/java/lang/String.html#matches(java.lang.String) esto devolverá boolean – ant

+3

@ c0mrade . partidos () hace lo mismo que Pattern.matches (, ), que hace lo mismo que Pattern.compile () .matcher () .matches() – Jared

+0

@Jared correcta, pero dijo que estaba usando el patrón/matcher no string coincide con – ant

Respuesta

13

Pruebe el método matcher.reset("newinputtext") para evitar crear nuevos mezcladores cada vez que llame a Pattern.matcher.

+4

Eso debería mejorar la velocidad hasta cierto punto ... vea mi prueba [ciertamente débil] aquí: http://pastie.org/2570213 – Jared

+0

@Jared: muy buena prueba. –

+3

Esto es bueno, pero tenga en cuenta que la clase Matcher no es segura para subprocesos. En un entorno de subprocesos, inicialice un Matcher para cada subproceso o simplemente use un Patrón estático precompilado (la clase de Patrón es segura para subprocesos pero eso le da el mismo problema de asignación de memoria con el que comenzó). – DavidMFrey

0

Puede intentar usar el método estático Pattern.matches() que simplemente devolverá el valor booleano. Eso no devolvería un objeto Matcher por lo que podría ayudar con los problemas de asignación de memoria.

Dicho esto, el patrón de expresión regular no sería precompilado, por lo que sería una cuestión de rendimiento vs recursos en el punto.

+5

'Pattern # matches' crea un Matcher objeto dentro de esa meta sobredosis. – jonderry

+0

@jonderry: Muy buen punto +1. En realidad, crea ambos, Patrón al compilar una expresión regular y crea Mather para la entrada dada. –

2

Si desea evitar la creación de un nuevo Matcher para cada patrón, utilice el método usePattern(), así:

Pattern[] pats = { 
    Pattern.compile("123"), 
    Pattern.compile("abc"), 
    Pattern.compile("foo") 
}; 
String s = "123 abc"; 
Matcher m = Pattern.compile("dummy").matcher(s); 
for (Pattern p : pats) 
{ 
    System.out.printf("%s : %b%n", p.pattern(), m.reset().usePattern(p).find()); 
} 

see the demo on Ideone

usted tiene que utilizar el método de coincidencias de reset() también, o find() solo buscará desde el punto donde terminó la partida anterior (suponiendo que la coincidencia fue exitosa).

4

Si espera menos del 50% de las líneas que coincidan con la expresión regular, primero puede tratar de probar por alguna subsecuencia través String.indexOf() que es aproximadamente de 3 a 20 veces más rápido para la secuencia simple en comparación con coincidencias de expresiones regulares:

if (line.indexOf("foo")>-1) && pattern.matcher(line).matches()) { 
    ... 

Si agrega a su código tales heurísticas, recuerde documentarlas siempre bien, y verificar el uso del generador de perfiles que el código es de hecho más rápido en comparación con el código simple.

+0

Y también agregue la prueba asegurando que la versión optimizada haga lo mismo o la expresión regular simple. Esto es útil si alguien cambia la expresión regular y se olvida del resto. – maaartinus

+0

Buena pista: esto también funciona para contener, y el partido no tiene que ser perfecto; solo necesita ser suficiente para reducir al menos un 50% la cantidad de elementos que van al patrón de emparejamiento. – Tadhg

Cuestiones relacionadas