Expresiones regulares en perl

De ChuWiki
Saltar a: navegación, buscar

Una de las cosas que hace interesante Perl es la potencia de sus expresiones regulares. Con ellas podemos analizar texto buscando palabras, combinaciones de letras o ciertos patrones.

Búsqueda básica

Si $cadena es una variable de cadena, podemos saber si contiene una subcadena de la siguiente forma

if ($cadena =~ /subcadena a buscar/ )

esta expresión devuelve true si $cadena contiene "subcadena a buscar". Las / sirven para delimitar la subcadena a buscar. Por ejemplo, lo siguiente daría true

$cadena = "hola";
if ($cadena =~ "ol")
{
   # es true, ya que "hola" contiene "ol"
}

Para ver si NO contiene la subcadena, se hace igual pero usando el símbo !~ en vez de el =~.

"hola" =~ /ol/  # es true, hola tiene ol
"hola" !~ /ol/  # es false, hola tiene ol

Hay una serie de caracteres especiales que se interpretan y no podemos poner directamente. Estos son

{}[]()^$.|*+?\

si queremos buscar uno de ellos en una cadena, debemos "escaparlo" anteponiendo un \

$cadena = "c:\directorio";
if ($cadena =~ /\\/)
{
   # es true. La \ hay que "escaparla" y se pone \\. 
   # $cadena contiene la \
}

Podemos cambiar el delimitador de búsqueda / por el que queramos, evitando así tener que "escapar" el / si queremos que forme parte de la cadena de búsqueda. Para ello, ponemos una m seguida del caracter que queremos usar

"hola" =~ m(ol);  # el delimitador es ( y )
"hola" =~ m"ol";  # el delimitador es " y "


Elección de posibles caracteres

Podemos elegir grupos de letras. Por ejemplo, si queremos saber si hay una palabra independientemente de si empieza con mayúscula o minúscula o si está en femenino o masculino, podemos poner

$cadena = "perro";
if ($cadena =~ /[Pp]err[oa]/ )
   ...

[Pp] equivale a una P o una p, luego "err" y finalmente una o o una a representado como [oa]. De esta forma, valdría Perro, perro, Perra, perra.

También podemos poner que NO sean esos caracteres, poniendo un ^ delante. Por ejemplo [^p] es cualquier cosa menos una p minúscula.

Si queremos, por ejemplo un número, podemos poner [0123456789]. Para simplificarlo, se puede poner una secuencia de caracteres seguidos de esta forma [0-9] equivale a cualquier cifra de 0 a 9. [a-z] equivale a cualquier letra minúscula desde la a a la z.

Para las combinaciones más habituales, tenemos definidas \s, \w y \d. El primero equivale a cualquier separador de palabra (espacio, tabulador, retorno de carro). El segundo a palabras con digitos y _ [0-9a-zA-Z_] y el tercero a cifras [0-9]. También tenemos los negados de estos. En la siguiente tabla se ve un resumen de todos ellos.

\d es equivalente a [0-9]
\s es equivalente a [\ \t\r\n\f]  (espacio, tabulador y retornos de carro)
\w es equivalente a [0-9a-zA-Z_]
\D es el negado de \d; Representa cualquier caracter que no sea un digito [^0-9]
\S es el negado de \s; Represnta cualquier cosa que no sea un espacio en blanco [^\s]
\W es el negado de  \w; Representa cualquier cosa que no sean cifras, letras o _ [^\w]

Número de veces que aparece el patrón

También se puede decir cuántas veces seguidas queremos que aparezca una secuencia, poniendo detrás un caracter o grupo de caracteres que lo especifiquen

a* es una a cero o más veces.
a+ es una a una o más veces.
a? es una a una o ninguna veces.
a{n} es una a n veces.
a{n,} es una a n o más veces.
a{n,m} es una a entre n y m veces, incluidos ambos valores.

Por supuesto, podemos usarlo con cualquier combinación de las anteriores

\d+ Un dígito una o más veces, es decir, un número completo con todos sus dígitos.


Algunos caracteres especiales

El símbolo ^ equivale al principio de la cadena. Así es cierto

$cadena = "Perro";
if ($cadena =~ /^Perro/)
   # es cierto, Perro está al principio de la cadena

pero es falso

$cadena = "un perro";
if ($cadena =~ /^perro/)
   # es falso, perro no está al principio de la cadena

De la misma forma, el $ equivale a final de cadena.

El punto . equivale a cualquier caracter. Por ello /.erro/ es cierto para "Perro", "perro", pero también para "cerro", "berro"


Obtener las cadenas buscadas

A veces es interesante saber cual es exactamente la cadena de caracteres que encaja con nuestro patrón, para que nuestro programa haga cosas con ella. Por ejemplo, si tenemos una cadena con una distancia y sus unidades, quizás queramos obtener tanto el número como la unidad. Por ejemplo, de "10 km" nos interesa el 10 y km. De "20 m" nos interesa 20 y m.

Para poder obtener las subacadenas, basta encerrar el patrón entre parénteis. De esta forma

"20 m" =~ /(\d+)\s+(\w+)/

Este patrón busca uno o más dígitos \d+, luego uno o más espacios \s+ y luego una o más letras \w+. Los trozos encerrados entre paréntesis se meterán en las variables especiales $1, $2, $3, consecutivamente. De esta forma, después de ejecutar esa búsqueda, tendremos

$1 será "20"
$2 será "m"
$3 y siguientes estarán vacíos.

Quizás nos interese saber si la misma palabra aparece exactamente dos veces. Dentro de la cadena de búsqueda podemos poner \1, \2, etc para hacer referencia a las variables $1, $2 obtenidas en la misma búsqueda. Por ejemplo si queremos saber en "palabra1:palabra2" si palabra1 y palabra2 son la misma, podemos poner esto

"palabra1:palabra2" =~ /(\w+):\1/

Primero buscará una palabra con \w+ y la guardará en $1, ya que está entre paréntesis, luego buscará el dos puntos y luego buscará algo que coincida con $1. Es decir, si palabra1 y palabra2 son iguales, eso devolverá true, en caso contrario devolverá false.


Enlaces

En perfecto inglés, pero son los tutoriales más completos que he encontrado sobre el tema