Cómo utilizar expresiones regulares
En la versión Java JDK 1.40 de Sun, Java viene con un paquete que admite expresiones regulares. Este artículo presenta brevemente cómo utilizar el paquete java.util.regex.
Se puede estimar aproximadamente que, excepto aquellos que ocasionalmente usan Linux, otros usuarios de Linux encontrarán expresiones regulares. Las expresiones regulares son herramientas extremadamente poderosas y flexibles en términos de coincidencia y reemplazo de patrones de cadenas. En el mundo Unix las expresiones regulares tienen pocas limitaciones, pero lo cierto es que son muy utilizadas.
Muchas herramientas comunes de Unix han implementado motores de expresiones regulares, incluidos grep, awk, vi y Emacs. Además, muchos lenguajes de scripting ampliamente utilizados también admiten expresiones regulares, como Python, Tcl, JavaScript y el más famoso Perl.
He sido un hacker de Perl durante mucho tiempo y, si eres como yo, dependes en gran medida de tener a tu disposición estas poderosas herramientas de edición de texto. En los últimos años, al igual que otros desarrolladores de programas, he prestado cada vez más atención al desarrollo de Java.
Como lenguaje de desarrollo, Java tiene muchas cosas que recomendar, pero no siempre ha tenido soporte integrado para expresiones regulares. Hasta hace poco, Java comenzó a admitir expresiones regulares con la ayuda de bibliotecas de terceros, pero estas bibliotecas de terceros son inconsistentes, tienen poca compatibilidad y el código es terrible de mantener. Esta deficiencia siempre ha sido una gran preocupación para mí al elegir Java como mi principal herramienta de desarrollo.
¡Puedes imaginar lo feliz que me sentí cuando supe que la versión Java JDK 1.40 de Sun incluye java.util.regex (un paquete de expresiones regulares autónomo y completamente abierto! ¡Es muy divertido! ¡Dime, gasté algo de tiempo! tiempo profundizando en esta joya escondida. Estoy muy sorprendido de que una mejora tan grande en Java (viene con el paquete java.util.regex) ¿Por qué no se hace más pública?
Recientemente, Java ha saltado a las expresiones regulares con ambos pies. . mundo del estilo. El paquete java.util.regex también tiene la ventaja de admitir expresiones regulares. Además, Java también proporciona documentación relacionada detallada. La brumosa y misteriosa escena de expresiones regulares se fue revelando lentamente. Hay algunas construcciones de expresiones regulares (quizás las más notables, aquellas que incorporan bibliotecas de caracteres) que no se encuentran en Perl.
En el paquete regex, hay dos clases, Pattern (clase de patrón) y Matcher (clase de coincidencia). La clase Pattern es un objeto utilizado para expresar y establecer el patrón de búsqueda, y la clase Matcher es el objeto que realmente afecta la búsqueda. Se agrega una nueva clase de excepción, PatternSyntaxException, que generará una excepción cuando se encuentre un patrón de búsqueda ilegal.
Incluso si está familiarizado con las expresiones regulares, encontrará que usar expresiones regulares a través de Java es bastante simple. Un punto a tener en cuenta es que para aquellos entusiastas de Perl que están mimados por la coincidencia de una sola línea de Perl, usar el paquete regex de Java para realizar operaciones de reemplazo será más problemático que su método habitual.
La limitación de este artículo es que no es un tutorial completo sobre el uso de expresiones regulares. Si los lectores desean obtener más información sobre las expresiones regulares, se recomienda leer Mastering Regular Expressions de Jeffrey Frieldl, publicado por O'Reilly Publishing House. Daré algunos ejemplos a continuación para enseñar a los lectores cómo usar expresiones regulares y cómo usarlas de manera más simple.
Diseñar una expresión sencilla que haga coincidir cualquier dígito de un número de teléfono puede resultar complicado porque existen muchos formatos de números de teléfono diferentes. Todos deben elegir un modo más eficaz.
Por ejemplo: (212) 555-1212, 212-555-1212 y 212 555 1212. Algunas personas pueden pensar que todos son equivalentes.
Primero formemos una expresión regular. Para hacerlo simple, formemos una expresión regular para reconocer los dígitos del número de teléfono en el siguiente formato: (nnn)nnn-nnnn.
El primer paso es crear un objeto de patrón que coincida con la subcadena anterior. Una vez que el programa se está ejecutando, el objeto se puede generalizar si se desea. La expresión regular que coincide con el formato anterior se puede formar de la siguiente manera: (\d{3})\s\d{3}-\d{4}, donde el tipo de carácter único \d se utiliza para hacer coincidir cualquier número del 0 al 9, y { 3} El símbolo de repetición es una notación simple que se usa para indicar que hay tres dígitos consecutivos, y también es equivalente a (\d\d\d). \s también es otro tipo de carácter único útil, que se utiliza para hacer coincidir espacios, como la tecla Espacio, la tecla de tabulación y el carácter de nueva línea.
¿No es muy simple? Sin embargo, si este patrón de expresión regular se usa en un programa java, se deben hacer dos cosas. Para el intérprete de Java, los caracteres antes de la barra invertida (\) tienen un significado especial. En Java, no todos los paquetes relacionados con expresiones regulares comprenden y reconocen el carácter de barra invertida (\), aunque puedes intentarlo. Pero para evitar esto, es decir, para permitir que el carácter de barra invertida (\) se pase completamente en el objeto de patrón, se debe utilizar un carácter de barra invertida doble (\). Además, los paréntesis tienen dos significados en las expresiones regulares. Si desea que se interpreten literalmente (es decir, paréntesis), también debe utilizar un carácter de doble barra invertida (\) delante. Es decir, como lo siguiente:
\\(\\d{3}\\)\\s\\d{3}-\\d{4}
Ahora Presente cómo implementar la expresión regular que acabamos de mencionar en el código Java. Una cosa para recordar es que cuando utilice un paquete de expresión regular, debe incluir el paquete antes de la clase que defina, que es una línea como esta:
import java.util.regex.*;< / p>
El siguiente fragmento de código implementa la función de leer línea por línea de un archivo de texto y buscar dígitos de números de teléfono línea por línea. Una vez que se encuentra una coincidencia, se envía a la consola.
BufferedReader en
Patrón patrón = Pattern.compile("\\(\\d{3}\\)\\s\\d{3}-\\d {4}");
in = new BufferedReader(new FileReader("teléfono"));
String s;
while ((s = in .readLine()) != null)
{
Coincidente matcher = patrón.matcher(s);
if (matcher.find())
{
System.out.println(matcher.group());
}
}
in.close();
Para aquellos familiarizados con la implementación de expresiones regulares en Python o Javascript, este código les parecerá trivial. En lenguajes como Python y Javascript, u otros lenguajes, una vez que estas expresiones regulares se compilan explícitamente, puedes usarlas donde quieras. En comparación con la coincidencia de un solo paso de Perl, parece un poco más trabajoso, pero no es muy problemático.
El método find(), como se puede imaginar, se usa para buscar cualquier cadena de destino que coincida con la expresión regular, y el método group() se usa para devolver una cadena que contiene el texto coincidente. Cabe señalar que el código anterior solo se usa cuando cada línea solo puede contener una cadena numérica de número de teléfono coincidente. Se puede decir con certeza que el paquete de expresiones regulares de Java se puede utilizar para buscar cuando una línea contiene varios objetivos coincidentes. La intención original de este artículo es brindar algunos ejemplos simples para inspirar a los lectores a aprender más sobre el paquete de expresiones regulares que viene con Java, por lo que no hay una discusión en profundidad sobre esto.
¡Esto es genial! Pero desafortunadamente, esto es solo un comparador de números de teléfono. Evidentemente hay dos puntos que podrían mejorarse. Si está al principio del número de teléfono, puede haber un espacio entre el código de área y el número local. También podemos hacer coincidir estas situaciones agregando \s? a la expresión regular, donde el metacarácter ? indica que puede haber 0 o 1 carácter de espacio en el patrón.
El segundo punto es que puede haber espacios entre los primeros tres y los últimos cuatro dígitos del número local en lugar de guiones, o mejor aún, puede que no haya ningún separador, es decir, 7 dígitos conectados entre sí. . Para estas situaciones, podemos usar (-|)? La expresión regular de esta estructura es el convertidor, que puede coincidir con las situaciones mencionadas anteriormente. Cuando () puede contener el carácter de barra vertical |, puede coincidir si contiene un carácter de espacio o un guión, y el metacarácter final indica si no hay ningún delimitador.
Finalmente, el número de ubicación no puede estar entre paréntesis. Para esto, simplemente puede agregar el metacarácter ? después del paréntesis, pero esta no es una buena solución. Porque también contiene paréntesis no coincidentes, como "(555" o "555)". En su lugar, podemos forzar que el número de teléfono incluya paréntesis mediante otro convertidor: (\(\d{3}\)|\d{3}). Si reemplazamos las expresiones regulares en el código anterior con estas mejoradas, el código anterior se convierte en un comparador de números de teléfono muy útil:
Pattern patrón =
Pattern.compile("(\ \(\\d{3}\\)|\\d{3})\\s?\\d{3}(-|)?\\d{4}" );
Sin duda, puede intentar mejorar aún más el código anterior usted mismo.
Ahora mira el segundo ejemplo, adaptado del de Friedl. Su función es comprobar si hay palabras repetidas en archivos de texto, lo que suele ocurrir en la impresión y la composición tipográfica. También es un problema con los correctores gramaticales.
La coincidencia de palabras, como todo lo demás, se puede lograr con varias expresiones regulares. Probablemente el más sencillo es \b\w \b, que tiene la ventaja de requerir sólo una pequeña cantidad de metacaracteres de expresiones regulares. El metacarácter \w se utiliza para hacer coincidir cualquier carácter de las letras a a u. El metacarácter indica la coincidencia de uno o más caracteres. El metacarácter \b se utiliza para describir el límite de la palabra coincidente. Puede ser un espacio o cualquier signo de puntuación diferente (incluyendo coma, punto, etc.).
Ahora bien, ¿cómo comprobamos si una palabra determinada se repite tres veces? Para realizar esta tarea, necesitamos hacer pleno uso del conocido escaneo hacia atrás en las expresiones regulares. Como se mencionó anteriormente, los paréntesis tienen varios usos diferentes en las expresiones regulares. Uno es proporcionar un tipo de combinación. El tipo de combinación se usa para guardar el resultado coincidente o el resultado coincidente parcial (para que pueda usarse más adelante), incluso si se encuentra el mismo. patrón. Dentro de la misma expresión regular, es posible (y normalmente se espera) tener más de un tipo de combinación. El resultado coincidente en el enésimo tipo de combinación se puede obtener escaneando hacia atrás. Escanear hacia atrás hace que la búsqueda de palabras duplicadas sea muy simple: \b(\w )\s \1\b.
Los paréntesis forman un tipo de combinación, que es el primer (y único) tipo de combinación en esta representación regular. Escanee hacia atrás \1, que se refiere a cualquier palabra que coincida con \w.
Por lo tanto, nuestra expresión regular coincidirá con una palabra que tenga uno o más espacios en blanco seguidos de una palabra idéntica. Tenga en cuenta que el tipo de posicionamiento final (\b) es esencial para evitar errores. Si queremos hacer coincidir "París en primavera" en lugar de "el paquete de expresiones regulares de Java es el tema de este artículo". Según el formato actual de Java, la expresión regular anterior es: Patrón patrón =Pattern.compile("\\b(\\w )\\s \\1\\b");
Finalmente Una modificación adicional sería hacer que nuestro comparador distinga entre mayúsculas y minúsculas. Por ejemplo, la siguiente situación: "El tema de este artículo es el paquete de expresiones regulares de Java". Esto se puede lograr de manera muy simple en expresiones regulares usando el indicador estático CASE_INSENSITIVE predefinido en la clase Patrón:
Patrón patrón = Pattern.compile("\\b(\\w )\\s \\1\\b",
Pattern.CASE_INSENSITIVE);
Relacionado El tema de las expresiones regulares es rico y complejo, y su implementación en Java es tan extensa que requiere un estudio exhaustivo del paquete regex. Lo que hemos cubierto aquí es sólo la punta del iceberg. Incluso si es nuevo en el uso de expresiones regulares, descubrirá rápidamente su poder y escalabilidad después de usar el paquete regex. Si es un hacker experimentado en expresiones regulares de Perl u otro reino lingüístico, después de usar el paquete regex, se sumergirá tranquilamente en el mundo de Java, abandonará otras herramientas y considerará el paquete regex de java como algo imprescindible. herramienta para tener a mano.