util sheet matches cheat java regex

sheet - java.util.regex: importancia de Pattern.compile()?



java util regex (6)

¿Cuál es la importancia del método Pattern.compile() ?
¿Por qué necesito compilar la cadena de expresiones regulares antes de obtener el objeto de Matcher ?

Por ejemplo :

String regex = "((//S+)//s*some//s*"; Pattern pattern = Pattern.compile(regex); // why do I need to compile Matcher matcher = pattern.matcher(text);


Cuando compila el Pattern Java hace algunos cálculos para hacer que encontrar coincidencias en String más rápido. (Crea una representación en memoria de la expresión regular)

Si va a reutilizar el Pattern varias veces, verá un gran aumento en el rendimiento sobre la creación de un nuevo Pattern cada vez.

En el caso de utilizar solo el patrón una vez, el paso de compilación parece una línea de código adicional, pero, de hecho, puede ser muy útil en el caso general.


El método compile() siempre se llama en algún punto; es la única forma de crear un objeto Pattern. Entonces, la pregunta es, ¿por qué debería llamarlo explícitamente ? Una razón es que necesita una referencia al objeto Matcher para que pueda usar sus métodos, como group(int) para recuperar los contenidos de los grupos de captura. La única forma de obtener el objeto Matcher es a través del método matcher() del objeto Pattern, y la única manera de obtener el objeto Pattern es a través del método compile() . Luego está el método find() que, a diferencia de matches() , no está duplicado en las clases String o Pattern.

La otra razón es evitar crear el mismo objeto Pattern una y otra vez. Cada vez que utilizas uno de los métodos de expresión regex en String (o el método de matches() estáticas matches() en Pattern), crea un nuevo patrón y un nuevo Matcher. Entonces, este fragmento de código:

for (String s : myStringList) { if ( s.matches("//d+") ) { doSomething(); } }

... es exactamente equivalente a esto:

for (String s : myStringList) { if ( Pattern.compile("//d+").matcher(s).matches() ) { doSomething(); } }

Obviamente, eso está haciendo un montón de trabajo innecesario. De hecho, puede tardar más tiempo en compilar la expresión regular y crear una instancia del objeto Pattern, que en realizar una coincidencia real. Entonces, por lo general, tiene sentido sacar ese paso del ciclo. También puede crear el Matcher con anticipación, aunque no son tan caros:

Pattern p = Pattern.compile("//d+"); Matcher m = p.matcher(""); for (String s : myStringList) { if ( m.reset(s).matches() ) { doSomething(); } }

Si está familiarizado con las expresiones regulares de .NET, se estará preguntando si el método compile() Java está relacionado con el modificador RegexOptions.Compiled de .NET; la respuesta es no. El método Pattern.compile() Java es simplemente equivalente al constructor Regex de .NET. Cuando especifica la opción Compiled :

Regex r = new Regex(@"/d+", RegexOptions.Compiled);

... compila la expresión regular directamente al código de byte CIL, lo que le permite funcionar mucho más rápido, pero a un costo significativo en el procesamiento inicial y en el uso de la memoria. Piénselo como esteroides para los regexes. Java no tiene equivalente; no hay diferencia entre un patrón creado detrás de escena por String#matches(String) y uno que crea explícitamente con Pattern#compile(String) .

(EDITAR: Originalmente dije que todos los objetos .NET Regex están en caché, lo cual es incorrecto. Desde .NET 2.0, el almacenamiento en caché automático ocurre solo con métodos estáticos como Regex.Matches() , no cuando se llama directamente a un constructor Regex. ref )


Es cuestión de rendimiento y uso de la memoria, recopile y mantenga el patrón cumplido si necesita usarlo mucho. Un uso típico de regex es validar la entrada del usuario (formato) , y también formatear los datos de salida para los usuarios , en estas clases, guardar el patrón cumplido, parece bastante lógico, ya que generalmente llaman mucho.

A continuación se muestra un validador de muestra, que realmente se llama mucho :)

public class AmountValidator { //Accept 123 - 123,456 - 123,345.34 private static final String AMOUNT_REGEX="//d{1,3}(,//d{3})*(//.//d{1,4})?|//.//d{1,4}"; //Compile and save the pattern private static final Pattern AMOUNT_PATTERN = Pattern.compile(AMOUNT_REGEX); public boolean validate(String amount){ if (!AMOUNT_PATTERN.matcher(amount).matches()) { return false; } return true; } }

Como menciona @Alan Moore, si tiene regex reutilizable en su código, (antes de un ciclo, por ejemplo), debe compilar y guardar el patrón para su reutilización.


La compilación analiza la expresión regular y crea una representación en memoria . La sobrecarga para compilar es significativa en comparación con una coincidencia. Si está utilizando un patrón repetidamente , obtendrá algún rendimiento para almacenar en caché el patrón compilado.


Precompilar la expresión regular aumenta la velocidad. Volver a utilizar el Matcher te da otra ligera aceleración. Si se llama al método con frecuencia, digamos que se llama dentro de un bucle, el rendimiento general ciertamente aumentará.


Similar a ''Pattern.compile'' hay ''RECompiler.compile'' [de com.sun.org.apache.regexp.internal] donde:
1. código compilado para el patrón [az] tiene ''az'' en él
2. código compilado para el patrón [0-9] tiene ''09'' en él
3. El código compilado para el patrón [abc] tiene ''aabbcc'' en él.

Por lo tanto, el código compilado es una excelente manera de generalizar casos múltiples. Por lo tanto, en lugar de tener diferentes códigos, se maneja la situación 1,2 y 3. El problema se reduce a la comparación con el ascii del elemento presente y siguiente en el código compilado, de ahí los pares. Así
a. cualquier cosa con ascii entre a y z es entre a y z
segundo. cualquier cosa con ascii entre ''a y a es definitivamente'' a ''