Se puede decir que Regular Expressions es como "Find and Replace" en cualquier lenguaje (o bien, aplicación).
Muchos lenguages de programación cuentan con una función parecido a substr de Perl (ver perldoc -f substr para detalles), pero el uso de Regular Expressions es mucho más flexible.
La diferencia de un "Find and Replace" y Regular Expressions es que un "Find and Replace" normalmente solo permite la búsqueda y el reemplazo de la cadena que se escribe literalmente.
Un ejemplo:
Microsoft Word cuenta con "Find and Replace". Quiero encontrar la cadena 'Bill' en un documento. O me dice "Falló la búsqueda" si no la encuentra, o me dice que use F3 para que siga buscando. Pero como hago si quisiera poner la condición: "Que falle la búsqueda si no encuentro la cadena 'Bill' 3 veces o más en el documento? En Microsoft Word no se puede hacer esto. Microsoft Word obviamente no está escrito en Perl. ;-)
Expresión
Significado
$variable =~ m/RegExp/
Evalua a Verdad si se encuentra una cadena que corresponde al RegExp en $variable.
$variable !~ m/RegExp/
Evalua a Verdad si NO se encuentra una cadena que corresponde al RegExp en $variable.
$variable =~ s/RegExp1/RegExp2/
Se sustituye una cadena que corresponde al RegExp1 a otra que corresponde a RegExp2 en $variable.
En la forma más simple se ve el uso de Regular Expressions en el siguiente ejemplo:
my $salud = 'Hi there!';
# Match using 'm//'
if ($salud =~ m/Hi/) {
print "Found 'Hi' in '$salud'\n";
}
# Substitute using 's///'
$salud =~ s/Hi/Hello/;
if ($salud =~ m/Hello/) {
print "Found 'Hello' in '$salud'\n";
}
if ($salud !~ m/Hi/) {
print "Did not find 'Hi' any longer in '$salud'\n";
}
En el ejemplo arriba, la expresión ($salud =~ m/Hi/) evalua a Verdad si el variable $salud "hace Match" a la cadena Hi.
La expresión ($salud !~ m/Hi/) evalua a Verdad si el variable $saludno "hace Match" a la cadena Hi.
Tarea: Hacer un programa que sustituye tu nombre por tu apellido.
En el ejemplo arriba solo usamos las cadenas fijas Hi y Hello en nuestras Regular Expressions.
Hay ciertos caracteres que tienen sentido especial en Regular Expressions, llamados Metacharacters.
Los metacharacters no "hacen Match" a si mismos. Mientras la expresión m/J/ hace match a una J mayúscula, la expresión m/$/no "hace Match" al signo de dolar.
Abajo el significado de cada uno.
Metcharacter
Significado
\
Se usa para poder hacer Match de un Metcharacter.
La expresión m/\$/ hace Match al signo dolar, m/\+\*\\\?/ hace match a la cadena +*\?
Cuando el \ antecede un caracter que no es Metacharacter, cambia el significado del caracter.
Por ejemplo, \n no hace Match a los dos caracteres \ y n, sino a un Newline <LF>, \t hace match a una tabulación <TAB> etc.
Vea abajo una lista completa de estos caracteres.
|
Se parece al logical OR ||, aplicado en un RegExp.
La expresión /Fred|Wilma|Barney|Betty/ hace Match si encuentra a Fred OR Wilma OR Barney OR Betty.
()
Se usa para agrupar partes de una RegExp.
La expresión /(Fred|Wilma|Pebbles) Flintstone/ hace Match a 'Fred Flinstone', 'Wilma Flintstone' y 'Pebbles Flinstone'.
[]
Se usa para definir intervalos.
La expresión /[a-z]/ hace Match a cualquier letra en el alfabeto inglés (sólo minúscula), la expresión /[A-Za-z]/ tanto a mayúscula como a minúscula, /[A-Za-z_0-9]/ hace match a caracteres alfanuméricos.
[]
Se usa para definir Quantifiers (vea abajo de Quantifiers).
La expresión /a{5}/ hace Match a la cadena 'aaaaa', la expresión /abc{3}/ hace Match a la cadena 'abccc', la expresión /(abc){3}/ hace Match a la cadena 'abcabcabc', /a{2,4}/ hace match a las cadenas 'aa', 'aaa' y 'aaaa', pero no a las cadenas 'a' ni 'aaaaa', /a{2,}/ hace Match a cadenas con dos o más 'a':s seguidas.
^
Se usa para hacer Match desde el inicio de un variable.
La expresión /qwerty/ hace Match a la cadena 'XXXqwertyYYY', pero no la expresión /^qwerty/, que sólo hace Match a cadenas como 'qwerty', 'qwertyXXX', 'qwertyXXXYYY', o sea requiere que la cadena inicia con el RegExp.
$
Se usa para hacer Match desde la final de un variable.
La expresión /qwerty$/ no hace Match a la cadena 'XXXqwertyYYY', sólo a cadenas como 'qwerty', 'XXXqwerty', 'XXXYYYqwerty', o sea requiere que la cadena finaliza con el RegExp.
* + ?
Quantifiers especiales, no se definen con {} (vea arriba).
La expresión /a*/ es idéntica a /a{0,}/, quiere decir que hace match a cadenas con 0 o más 'a':s.
La expresión /a+/ es idéntica a /a{1,}/, quiere decir que hace match a cadenas con 1 o más 'a':s.
La expresión /a?/ es idéntica a /a{0,1}/, quiere decir que hace match a cadenas con 0 o 1 'a':s.
.
El punto (.) hace match a cualquier letra menos NewLine <NL>.
Tareas:
Definir una expresion que hace Match a 2 Newline:s <NL>:s consecutivos.
Definir una expresion que hace Match a 'Juan' o a 'Pedro'.
Definir una expresion que hace Match a 'Juan Lopez' o a 'Juan Perez'.
Definir una expresion que hace Match a cualquier letra D,E,F,G,H,I,J,K,L.
Definir una expresion que hace Match a 'abc' pero no a '123abc'.
Definir una expresion que hace Match a 'abc' pero no a 'abc123'.
Definir una expresion que hace Match a 'z' y a 'zzz', pero no a 'zz'.
Como mencionado arriba, cuando el Metacharacter \ antecede ciertos caracteres, cambia el significado del caracter.
Ya mencionamos \t y \n, TAB y NL, el \r también es común cuando se tratan de archivos DOS. En DOS cada linea termina con <CR><LF>, UNIX sólo con <LF>.
Un caracter que no se usa mucho hoy en día es el Form Feed <FF>, pero lo mencionamos aquí como \f.
Estos caracteres corresponden a un caracter especial, pero es un caracter ASCII.
Los siguientes caracteres no corresponden directamente a un caracter ASCII:
Caracter especial
Significado
\d
Hace Match a un dígito.
La expresión /\d/ es idéntica a /[0-9]/.
\D
Hace Match a cualquier caracter que no sea un dígito, o sea, \D es lo opuesto a \d.
\s
Hace Match a un caracter 'de espacio'. Como 'espacio' se cuenta ' ', TAB, NL, CR y FF.
Así, la expresión /\s/ es idéntica a /[ \t\n\r\f]/.
\S
Lo opuesto de \s.
\w
Hace Match a un caracter alfanumérico.
La expresión /\w/ es idéntica a /[a-zA-Z_0-9]/.
\W
Lo opuesto de \w.
\b
'Word boundary', 'límite de palabra'.
Hace Match donde inicia o termina una palabra.
Esto es donde un caracter no alfanúmerico \W antecede un caracter alfanumérico \w, o vice versa.
NOTA: Un caracter no alfanumérico no es lo mismo como un caracter 'de espacio', sino también incluyen otros caracteres no alfanuméricos, como los Metacharacters.
\B
Lo opuesto de \b, o sea, hace Match donde sea menos en el 'limite de palabra'.
Tareas:
Definir una expresion que sustituye <CR><LF> por <LF>.
Definir una expresion que hace Match a 8, 234, 7891 y 55, pero no a 'e33'.
Definir una expresion que hace Match a cualquier cadena que no contenga números.
Definir una expresion que sustituye dos o más espacios por uno.
Ya mencionamos los Quantifiers, definidos por {}, o bien los especiales * + ?. {n,m} significa que se requiere match de mínimo n veces y de máximo m veces. {n,} significa que se requiere match de mínimo n veces. {n} significa que se requiere match exactamente y únicamente n veces.
Tarea: Definir una expresión que hace Match a palabras más largas que 20 letras.
Patter-Matching operators se agregan al final de una expresión, por ejemplo s/This/That/g.
Patter-Matching Operator
Significado
e
'e as in Evaluate'.
La cadena de sustitución se evalua, puede ser una función.
Ejemplo: $variable =~ s/Mazda/&TodaysCar()/e
Sustituye la cadena Mazda po lo que devuelve la función &TodaysCar().
g
'g as in Globally'.
Hace match o sustituye globalmente, o sea todos los matches.
Ejemplo:
'i as in Insensitive'.
Hace match o sustituye case-insensitive.
Ejemplo:
/ABC/ hace match a 'ABC'
/ABC/i hace match a "ABc', AbC', etc.
m
'm as in Multiple'.
Si una cadena contiene <NL>, trata la cadena como varias lineas.
Esto hace que ^ y $ hacen match al inicio y final a cada linea respectivamente.
s
's as in Single'.
Aunque una cadena contiene <NL>, trata la cadena como una sola.
Esto hace que ^ y $ sólo hacen match al inicio y final a toda la cadena.
Tarea: Leer un archivo de texto a una cadena, hacer match a cada linea que termina en punto (.).
Hay que hacer una lista grandes de ejemplos para entender Regular Expressions.
(Y aún así cuesta. :-)
Muchas veces uno quiere la cadena original, y una copia donde se aplican los cambios de una expresión:
En vez de:
$copia = $original;
$copia =~ s/Algo/Otro/;
se puede hacerlo en una sola linea:
($copia = $original) =~ s/Algo/Otro/;
Hay que tener cuidado donde se aplican los parentesis:
se puede hacerlo en una sola linea.
Los cambios van en $c:
($c = $o) =~ s/Algo/Otro/g;
pero abajo, $c devuelve el número de cambios:
$c = ($o =~ s/Algo/Otro/g);
La primera agrupación de una expresión se guarda en el variable $1, la segunda en $2, etc.
Esto es útil en sustituciones:
my $a = '123 abc';
# La primera agrupacion (\d+) - uno o mas digitos - va en $1
# La segunda agrupacion (\s+) - uno o mas espacios - va en $2
# La tercera agrupacion (\S+) - uno o mas 'no espacios' - va en $3
# $3$2$1 quiere decir que las tres agrupaciones van al reves
(my $b = $a) =~ s/(\d+)(\s+)(\S+)/$3$2$1/;
print "$a\n";
print "$b\n";
Imprime:
123 abc
abc 123
Ejemplo de usar la primera agrupación $1 en una función:
# El sub devuelve el numero en letras
sub my_reg_exp {
my $d = shift;
my @letras = ('cero','uno','dos','tres');
return $letras[$d];
}
my $a = '0123 3210 111';
# La primera agrupacion $1 hace match a un digito.
# Se reemplaza la agrupación por lo que devuelve la función.
# Nota que se necesita el Modifier 'e' para evaluar la función
# Nota que se necesita el Modifier 'g' para reemplazar todos los digitos.
# Sin 'g' solo reemplaza el primer digito.
(my $b = $a) =~ s/(\d)/&my_reg_exp($1)/ge;
print "$a\n";
print "$b\n";