Capítulo 5. Expresiones regulares
Realicemos un programa mucho más interesante. Es el momento de comprobar si una cadena satisface una descripción, que llamaremos patrón.
En estos patrones existen algunos caracteres y combinaciones de caracteres que tienen un significado especial, y son:
Tabla 5-1. Caracteres especiales en expresiones regulares
Símbolo | Descripción> |
[] | Especificación de rango. (p.e. [a-z] representa una letra en el rango de la a a la z |
\w | Letra o dígito; es lo mismo que [0-9A-Za-z] |
\W | Ni letra, ni dígito |
\s | Espacio, es lo mismo que [ \t\n\r\f] |
\S | No espacio |
\d | Dígito; es lo mismo que [0-9] |
\D | No dígito |
\b | Backspace (0x08) (sólo si aparece en una especificación de rango) |
\b | Límite de palabra (sólo si no aparece en una especificación de rango) |
\B | No límite de palabra |
* | Cero o más repeticiones de lo que precede |
+ | Una o más repeticiones de lo que precede |
[m,n] | Al menos m y como máximo n de lo que precede |
? | Al menos una repetición de lo que precede; es lo mismo que [0,1] |
| | Puede coincidir con lo que precede o con lo que sigue |
() | Agrupamiento |
El término común para esto patrones que utilizan este extraño vocabulario es expresión regular. En Ruby, como en Perl, normalmente están rodeadas por barras inclinadas en vez de por comillas dobles. Si nunca antes se ha trabajado con expresiones regulares, es probable que parezcan cualquier cosa excepto regulares, pero sería inteligente dedicar algún tiempo a familiarizarse con ellas. Tienen un poder expresivo en su concisión que puede evitar muchos dolores de cabeza (y muchas líneas de código) si se necesita realizar coincidencia de patrones o cualquier otro tipo de manipulación con cadenas de texto.
Por ejemplo, supongamos que queremos comprobar si una cadena se ajusta a esta descripción: “Comienza con una f minúscula, a la que sigue exactamente una letra mayúscula y opcionalmente cualquier cosa detrás de ésta, siempre y cuando no haya más letras minúsculas.” Si se es un experimentado programador en C probablemente se haya escrito este tipo de código docenas de veces, ¿verdad? Admitádmoslo, es difícil mejorarlo. Pero en Ruby sólamente es necesario solicitar que se verifique la cadena contra la siguiente expresión regular /^f[A-Z][^a-z]*$/.
Y que decir de “¿Contiene la cadena un número hexadecimal entre ángulos?” No hay problema.
ruby> def chab(s) # contiene la cadena un hexadecinal entre ángulos
ruby| (s =~ /<0[Xx][\dA-Fa-f]+>/) != nil
ruby| end
nil
ruby> chab «Este no es»
false
ruby> chab «¿Puede ser esta? (0x35)» # entre paréntesis, no ángulos
false
ruby> chab «¿O esta? <0x38z7e>» # letra errónea
false
ruby> chab «OK esta si; <0xfc0004>»
true
Aunque inicialmente las expresiones regulares pueden parecer enigmáticas, se gana rápidamente satisfacción al ser capaz de expresarse con tanta economía.
A continuación se presenta un pequeño programa que nos permitirá experimentar con las expresiones regulares. Almacenémoslo como regx.rb, se ejecuta introduciendo en la línea de comandos ruby regx.rb
# necesita un terminal ANSI!!!
st = «\033[7m»
en = «\033[m»
while TRUE
print «str> «
STDOUT.flush
str = gets
break if not str
str.chop!
print «pat> «
STDOUT.flush
re = gets
break if not re
re.chop!
str.gsub! re, «#{st}\\&#{en}»
print str, «\n»
end
print «\n»
El programa necesita dos entradas, una con la cadena y otra con la expresión regular. La cadena se comprueba contra la expresión regular, a continuación muestra todas las partes de la cadena que coinciden con el patrón en vídeo inverso.
No nos preocupemos de los detalles; analizaremos el código posteriormente.
str> foobar
pat> ^fo+
foobar
~~~
Lo resaltado es lo que aparecerá en vídeo inverso como resultado de la ejecución del programa. La cadena ’~~~’ es en beneficio de aquellos que usen visualizadores en modo texto.
Probemos algunos ejemplos más.
str> abc012dbcd555
pat> \d
abc012dbcd555
Sorprendentemente y como indica la tabla al principio de este capítulo: \d no tiene nada que ver el carácter d, sino que realiza la coincidencia con un dígito.
¿Qué pasa si hay más de una forma de realizar la coincidencia con el patrón?.
str> foozboozer
pat> f.*z
foozboozer
~~~~~~~~
se obtiene foozbooz en vez de fooz porque las expresiones regulares tratan de obtener la coincidencia más larga posible.
A continuación se muestra un patrón para aislar la hora de un campo limitada por dos puntos.
str> WedFeb 7 08:58:04 JST 2001
pat> [0-9]+:[0-9]+(:[0-9]+)?
WedFeb 7 08:58:04 JST 2001
~~~~~~~~
=~ es el operador de coincidencia con expresiones regulares; devuelve la posición en la cadena donde se ha producido una coincidencia o nil si no la hay.
ruby> «abcdef» =~ /d/
3
ruby> «aaaaaa» =~ /d/
nil
Otras fuentes para consultar:
- http://rubular.com/
- https://carlossanchezperez.wordpress.com/2013/06/30/expresiones-regulares-en-ruby-no-te-dejes-intimidar-primera-parte/
- http://www.elwebmaster.com/general/ruby-principiantes-expresiones-regulares
- http://linuxmanr4.com/2014/08/19/expresiones-regulares-con-ruby/
- http://picandocodigo.net/2013/expresiones-regulares-en-ruby/
Video — Sesión 8. Expresiones Regulares en Ruby.
¿Tienes alguna consulta?
¿Quieres compartir algún código?