Conociendo RegEx (Parte 2/2)
Continuamos con las Expresiones Regulares, esta vez veremos ejemplos un poco más complejo.
El anterior post lo puedes ver aquí Conociendo RegEx (Parte 1/2)
La cadena es como esta:
Sabemos que, como comienza con
Patrón:
Ahora, el siguiente caracter puede ser cualquier caracter menos la coma, porque será nuestro separador ¿cierto?. Entonces, usaremos el caracter ^ para negar la coma, y puede tener lo que sea: otros caracteres, u otros simbolos.. pero debemos cortar hasta que encuentre otro
Patrón:
Nuestro código completo sería algo así
El resultado será este:
Ahora, vayamos un poco más complejo: Necesito extraer de una cadena todos los numéricos telefónicos que sean de siete dígitos, pero:
Quiere decir: Que comience con tres dígitos (
Noten que hasta el espacio fue considerado como caracter.
Analícemos lo que sucede con este juego de caracteres:
Antes de realizar el código, analicemos qué va a pasar con los caracteres "xx".
Podemos suponer que buscará todas cadenas que terminan en "xx". Pero realmente tenemos dos posibles resultados. ¿cuáles? Recordemos que regex trabaja de izquierda a derecha y los caracteres leídos ya no son considerados. Por tanto, trabajando de izquierda a derecha, podemos predecir que el motor primero examina los primeros cuatro caracteres (del 0 al 3), encuentra los caracteres "xx" que están en la posición 2 y es considerado como el final de la primera cadena a extraer. Luego sigue hasta la otra posición xx que está en la posición 6.
¿está claro?
Ahora, existe otra posible solución si es que queremos buscar todas las cadenas que terminan con "xx", y es que puede ser este el resultado:
A esto es lo que se le llama greedy (o goloso). Para que la segunda respuesta se la correcta, el motor regex debe buscar la cadena de una manera golosa en toda la cadena antes de determinar cuál "xx" es el final. Por tanto, el segundo resultado es el correo.
Esta es el resultado de la ejecución con ese patrón
Si vemos la tabla anterior, para hacer que el caracter
Esto es todo por ahora.
Si te gustó, dale Like o +1;
si te es útil, compártelo. Es gratis
El anterior post lo puedes ver aquí Conociendo RegEx (Parte 1/2)
Extrayendo subcadenas
Aquí tenemos un caso un poco más complejo.
Imaginemos que tenemos en un cadena un listado separado por comas de todos los archivos que tenemos en una carpeta, y necesitamos tener los archivos que su nombre comience con
proj1
. La cadena es como esta:
proj3.txt,proj1sched.pdf,proj1,proj2,proj1.java
Sabemos que, como comienza con
proj1
, entonces nuestro patrón deberá tener esa cadenaPatrón:
proj1
Ahora, el siguiente caracter puede ser cualquier caracter menos la coma, porque será nuestro separador ¿cierto?. Entonces, usaremos el caracter ^ para negar la coma, y puede tener lo que sea: otros caracteres, u otros simbolos.. pero debemos cortar hasta que encuentre otro
proj1
. Entonces, el patrón será así:
Patrón:
proj1([^,])*
Nuestro código completo sería algo así
String nombres = "proj1.xls,proj3.txt,proj1sched.pdf,proj1,proj2,proj1.java"; String expression = "proj1([^,])*", source = nombres; Pattern p = Pattern.compile(expression); Matcher m = p.matcher(source); System.out.println("expression:" + m.pattern()); System.out.println("source:" + source); System.out.println(" index:01234567890123456789012345678901234567890"); System.out.println(" 0 1 2 3 4\n"); System.out.println("pos grupo:"); while (m.find()) { System.out.println(m.start() + " " + m.group()); }
El resultado será este:
expression:proj1([^,])* source:proj1.xls,proj3.txt,proj1sched.pdf,proj1,proj2,proj1.java index:01234567890123456789012345678901234567890 0 1 2 3 4 pos grupo: 0 proj1.xls 20 proj1sched.pdf 35 proj1 47 proj1.java
Ahora, vayamos un poco más complejo: Necesito extraer de una cadena todos los numéricos telefónicos que sean de siete dígitos, pero:
- Los 7 dígitos pueden estar contínuos. Ejemplo: 1234567
- Esté separado por un espacio entre la zona y el número: Ejemplo 123 4567
- O, tenga un guión: Ejemplo 123-4567
Calma, calma. Este es el patrón:
Patrón:
\d\d\d([-\s])?\d\d\d\d
Quiere decir: Que comience con tres dígitos (
\d
tres veces) luego que sea ninguno o solo uno (?
) del caracter guión (-
) o espacio en blanco (\s
), y al final cuatro dígitos (\d
cuatro veces).¿Se ve mejor? |
El punto
Otro caracter especial es el punto que significa: "cualquier caracter que este aquí, el que sea, ".
Por ejemplo:
Fuente:
ac abc a
Patrón:
a.c
Resultado
expression:a.c source:ac abc a c index:01234567890123456789012345678901234567890 0 1 2 3 4 pos grupo: 3 abc 7 a c
Noten que hasta el espacio fue considerado como caracter.
Greedy Quantifiers
No he encontrado alguna traducción correcta al español de este tipo de calificadores. ¿"Greedy" se podría traducir como goloso?. Bueno, ya lo veremos.
Cuando usamos los cuantificadores
*
, +
y ?
, podemos ajustar un poco su comportamiento llamados "greedy" (goloso), "reluctant" (sin ánimo) o "possessive" (posesivo). [Me recuerda al término Lazy para cargar datos]. Veamos un poco la sintaxis:?
es greedy,??
es reluctant, para ninguna o una vez*
es greedy,*?
es reluctant, para ninguna o una vez+
es greedy,+?
es reluctant, para ninguna o una vez
Fuente:
Patrón:
yyxxxxyxx
Patrón:
.*xx
Antes de realizar el código, analicemos qué va a pasar con los caracteres "xx".
Podemos suponer que buscará todas cadenas que terminan en "xx". Pero realmente tenemos dos posibles resultados. ¿cuáles? Recordemos que regex trabaja de izquierda a derecha y los caracteres leídos ya no son considerados. Por tanto, trabajando de izquierda a derecha, podemos predecir que el motor primero examina los primeros cuatro caracteres (del 0 al 3), encuentra los caracteres "xx" que están en la posición 2 y es considerado como el final de la primera cadena a extraer. Luego sigue hasta la otra posición xx que está en la posición 6.
¿está claro?
Ahora, existe otra posible solución si es que queremos buscar todas las cadenas que terminan con "xx", y es que puede ser este el resultado:
A esto es lo que se le llama greedy (o goloso). Para que la segunda respuesta se la correcta, el motor regex debe buscar la cadena de una manera golosa en toda la cadena antes de determinar cuál "xx" es el final. Por tanto, el segundo resultado es el correo.
Esta es el resultado de la ejecución con ese patrón
expression:.*xx source:yyxxxyxx index:01234567 pos grupo: 0 yyxxxyxx
Si vemos la tabla anterior, para hacer que el caracter
*
no sean tan goloso, debemos usar el cualificador *?
para que sea una búsquedareluctant o reacia.
expression:.*?xx source:yyxxxyxx index:01234567 0 pos grupo: 0 yyxx 4 xyxx
Esto es todo por ahora.
Si te gustó, dale Like o +1;
si te es útil, compártelo. Es gratis
Comentarios
Publicar un comentario
Si quieres hacer una pregunta más específica, hazla en los foros que tenemos habilitados en Google Groups
Ah! solo se permiten comentarios de usuarios registrados. Si tienes OpenID, bienvenido! Puedes obtener su OpenID, aquí: http://openid.net/