Expresiones Regulares

woden 1,489 views 65 slides Dec 16, 2011
Slide 1
Slide 1 of 65
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21
Slide 22
22
Slide 23
23
Slide 24
24
Slide 25
25
Slide 26
26
Slide 27
27
Slide 28
28
Slide 29
29
Slide 30
30
Slide 31
31
Slide 32
32
Slide 33
33
Slide 34
34
Slide 35
35
Slide 36
36
Slide 37
37
Slide 38
38
Slide 39
39
Slide 40
40
Slide 41
41
Slide 42
42
Slide 43
43
Slide 44
44
Slide 45
45
Slide 46
46
Slide 47
47
Slide 48
48
Slide 49
49
Slide 50
50
Slide 51
51
Slide 52
52
Slide 53
53
Slide 54
54
Slide 55
55
Slide 56
56
Slide 57
57
Slide 58
58
Slide 59
59
Slide 60
60
Slide 61
61
Slide 62
62
Slide 63
63
Slide 64
64
Slide 65
65

About This Presentation

Dentro del marco del Curso 2011 de Introducción a Perl realizado por el grupo Barcelona.pm


Slide Content

EXPRESIONES
REGULARES
    
Barcelona.pm
(CC) 2011
por cjuan
 Curso de Introducción de Perl

¿Qué es un Regex?
La potencia de Perl en el procesamiento de textos viene dado 
por las expresiones regulares.
Una expresión regular es un patrón que describe las 
características de un trozo de texto.
Una expresión regular interpreta los patrones y los aplica para 
modificar o buscar coincidencias en un texto.

¿Qué es un Regex?
Ejemplo del poder del Regex:
Tenemos el ADN de una rana
... GATAAACCCAGGTTTAGATACAAAA ...

¿Qué es un Regex?
... GATAAACCCAGGTTTA GATACAAAA ...
podemos buscar un trozo de la cadena de ADN y substituirla 
por otra cadena.
s/GATACA/ATACA/
consiguiendo la nueva secuencia de ADN:
... GATAAACCCAGGTTTA ATACAAAA ...

¿Qué es un Regex?
... GATAAACCCAGGTTTA ATACAAAA ...

Patrones Simples
Buscar un patrón en una cadena:
my $name = 'Modern Perl';
say $name if $name =~ m/Perl/;
                                            
                                            
      ¿'Modern Perl' contiene 'Perl'? entonces devuelve '1'
 
> Moderl Perl 
ero
pero no es lo mismo si $name vale 'Pelr'
 
    say $name if $name !~ m/Pelr/; 

Patrones Simples
Es lo mismo:
 
$name =~ m/Perl/;    <==>    $name =~ /Perl/; 
 
m/<patrón>/   <==>    /<patrón>/  
 

Patrones Simples
Substituir una cadena:
my $name = 'Barroque Perl';
$name =~ s/Barroque/Modern/; 
say $name;
 
ero

Patrones Simples
Substituir una cadena:
my $name = 'Barroque Perl';
$name =~ s/Barroque/Modern/; 
say $name;
 
 
> Modern Perl
ero

El comando qr// y combinaciones
El comando qr/<patrón>/ permite crear clases de carácteres 
que podemos combinar en la misma expresión. 
     
    

El comando qr// y combinaciones
El comando qr/<patrón>/ permite crear clases de carácteres 
que podemos combinar en la misma expresión. 
     
    my $phrase = 'Esto es Modern Perl ...';    
 
    my $string1 = qr/Modern/;
    my $string2 = qr/Perl/;
    say 'Eureka!! '.$phrase if $phrase =~ /$string1 $string2/;

El comando qr// y combinaciones
El comando qr/<patrón>/ permite crear clases de carácteres 
que podemos combinar en la misma expresión. 
     
    my $phrase = 'Esto es Modern Perl ...';    
 
    my $string1 = qr/Modern/;
    my $string2 = qr/Perl/;
    say 'Eureka!! '.$phrase if $phrase =~ /$string1 $string2/;
    > Eureka!! Esto es Modern Perl ...

Cuantificadores
Las expresiones regulares alcanzan una nueva dimensión con 
la ayuda de los cuantificadores.
 
Los cuantificadores permiten especificar como los 
componentes de una expresión pueden aparecer en la cadena 
de búsqueda.
   =

Cuantificadores
?    => 0 ó 1 aparición
 
m/ca?t/; 
iif ($string =~ m/ca?t/) 
{
  say 'puede ser ct o cat';
}

Cuantificadores
?    => 0 ó 1 aparición
 
m/ca?t/; 
 
+    => 1 ó más apariciones
 
m/ca+t/;  
 
iif ($string =~ m/ca+t/) 
{
  say 'puede ser cat o caaat';
}

Cuantificadores
?    => 0 ó 1 aparición
 
m/ca?t/; 
 
+    => 1 ó más apariciones
 
m/ca+t/;  
  
*    => 0 ó más apariciones
 
m/ca*t/; 
iif ($string =~ m/ca*t/) 
{
  say 'puede ser ct, cat o 
caaat';
}

Cuantificadores Numéricos
{n} => 'n' apariciones
 
m/ca{1}t/
iif ($string =~ m/ca{1}t/) 
{
  say 'exactamente cat';
}

Cuantificadores Numéricos
{n} => 'n' apariciones
 
m/ca{1}t/
 
{n, }    => 'n' ó más  
 
m/ca{1, }t/;  
 
iif ($string =~ m/ca{1, }t/) 
{
  say 'puede ser cat, caat, 
caaaa......at';
}

Cuantificadores Numéricos
{n} => 'n' apariciones
 
m/ca{1}t/
 
{n, }    => 'n' ó más  
 
m/ca{1, }t/;  
 
{n,m}    => entre 'n' y 'm'
 
m/ca{1,3}t/;  
iif ($string =~ m/ca{1,3}t/) 
{
  say 'puede ser cat, caat o 
caaat';
}

Cuantificadores Posesivos
+
    }  Los cuantificadores posesivos son traicioneros !!
*
 
Es decir, encuentran más de lo que deben. 
 
Ejemplo:
my $string_1 = 'la casa es grande y fria';
my $search = qr/casa.*gran/; 
 
 

Cuantificadores Posesivos
Ejemplo:
my $string_1 = 'la casa es grande y fria';
my $search = qr/casa.*gran/; 
 
1) /casa/ hace una búsqueda del patrón
2) /.*/ busca 0 ó más carácteres
3) /gran/ busca un patrón definido

Cuantificadores Posesivos
my $string_1 = 'la casa es grande y fria';
my $string_2 = 'casada y gran madre';
my $search = qr/casa.*gran/;
say 'encontre \'casa\' y \'gran\' en '.$string_1 
    if $string_1 =~ $search;
say 'encontre \'casa\' y \'gran\' en '.$string_2 
    if $string_2 =~ $search;

Cuantificadores Posesivos
my $string_1 = 'la casa es grande';
my $string_2 = 'casada y gran madre';
my $search = qr/casa.*gran/;
say 'encontre \'casa\' y \'gran\' en '.$string_1 
    if $string_1 =~ $search;
say 'encontre \'casa\' y \'gran\' en '.$string_2 
    if $string_2 =~ $search;
 
> encontre 'casa' y 'gran' en la casa es grande
> encontre 'casa' y 'gran' en casada y gran madre

Anclajes
\A => indica que la comparación debe ser en el principio del 
string.
\Z => indica que debe buscar el match al final de la linea dentro 
del string.
 
 

Anclajes
my $string = 'la URL es http://barcelonapm.wordpress.com';
my $search = qr/\A(barcelonapm).*/;
say $1 if $string =~ $search;
my $fichero = 'dupa.png';
my $search_ext = qr/(.*)\.(png)\Z/;
say 'mi archivo '.$2.' es '.$1 if $fichero =~ $search_ext;
 

Anclajes
my $string = 'la URL es http://barcelonapm.wordpress.com';
my $search = qr/\A(barcelonapm).*/;
say $1 if $string =~ $search;
my $fichero = 'archivo: dupa.png';
my $search_ext = qr/(.*)\.(png)\Z/;
say 'mi archivo '.$2.' es '.$1 if $fichero =~ $search_ext;
 
> (nada)
    (... el string no comienza con 'barcelonapm')
 
> mi archivo png es dupa
    (hace la comparación desde el final)

Anclajes de palabras
Esto   es   Modern   Perl
                                 -----    --    ---------    -----
                                    ^       ^         ^           ^ 
                                    |        |          |            |
 
                  Palabra     1      2        3           4
Con el metacaracter \b<palabra>\b podemos asegurar que  
encontraremos 'saca' y no 'casacamiento'
La contra será \B.
 
qr/\bcasa.*?\b/;
Encontrara 'casa' y 'casamiento' pero no 'encasado'                 
            

Anclajes de palabras
my $string = 'la URL es http://barcelonapm.wordpress.com';
my $search = qr/\b(barcelona.+?)\b/;
say $1 if $string =~ $search;

Anclajes de palabras
my $string = 'la URL es http://barcelonapm.wordpress.com';
my $search = qr/\b(barcelona.+?)\b/;
say $1 if $string =~ $search;
> barcelonapm
 

Anclajes de palabras
my $string = 'la URL es http://barcelonapm.wordpress.com';
my $search = qr/\b(barcelona.+?)\b/;
say $1 if $string =~ $search;
> barcelonapm
 
El límite de \b está entre un carácter de palabra y otro de no-
palabra. En este caso el punto (.) entre barcelonapm y 
wordpress.
Las palabras son secuencias de letras, dígitos y '_'
(barcelonapm, wordpress, com, ...)

Anclajes de palabras
my $string = 'la URL es http://barcelonapm.wordpress.com';
my $search = qr/\b(barcelona.+?)\b/;
say $1 if $string =~ $search;
> barcelonapm
 
El mismo ejemplo sin los metacarácteres \b nos sale:
my $search = qr/(barcelona.+?)/;
> barcelonap

Metacarácteres
Son carácteres especiales en las regex que son interpretados 
de manera diferente a un literal.
Esto ofrece muchas posibilidades al no depender solo de las 
subcadenas.

Metacarácteres
. busca cada carácter individual 
\t busca una tabulación 
\s busca un espacio o una tabulación 
\S busca todo carácter que no sea una tabulación 
\n busca una "newline" 
\w busca toda letra concreta, cifra y también ' _ '
\W busca todo lo que no sea una letra, una cifra o ' _ '
\d busca toda cifra individual de 0 a 9 
\D busca todo carácter que no sea una cifra 

Metacarácteres
my $phone = '93 234 43 56';
my $prefix = qr/\A(\d{2})\s(.+)/;
say 'Prefijo: '.$1.' número: '.$2 if $phone =~ $prefix;
 
 
\d{2} --> busca 2 carácteres numéricos
\s      --> busca un espacio en blanco
.+      --> cualquier carácter 1 ó más veces

Metacarácteres
my $phone = '93 234 43 56';
my $prefix = qr/\A(\d{2})\s(.+)/;
say 'Prefijo: '.$1.' número: '.$2 if $phone =~ $prefix;
 
 
 
> Prefijo: 93 número: 234 43 56

Metacarácteres
my $string = 'Si todos los derechos son reservados
¿son todos los zurdos muy habladores?';
 
my $search = qr/(\n.*)/;
say $1 if $string =~ $search;
(después de la palabra reservados hay una nueva linea)

Metacarácteres
my $string = 'Si todos los derechos son reservados
¿son todos los zurdos muy habladores?';
 
my $search = qr/(\n.*)/;
say $1 if $string =~ $search;
> ¿son todos los zurdos muy habladores?

Clases de carácteres
Cuando ninguno de los metacarácteresse ajusta a nuestro 
patrón podemos crear nuestras clases de carácteres.
Para especificar una clase de carácter lo encerramos entre 
corchetes [ ]

Clases de carácteres
Cuando ninguno de los metacarácteresse ajusta a nuestro 
patrón podemos crear nuestras clases de carácteres.
Para especificar una clase de carácter lo encerramos entre 
corchetes [ ]
Por ejemplo:
my $vocals = qr/[aeiou]/;
my $pares = qr/[2468]/;

Clases de carácteres
my $string = '1 ó 2 pajaritos en la fuente';
my $vocals = qr/([aeiou])/;
my $pares = qr/([2468])/;
say 'vocales: '.$1 if $string =~ $vocals;
say 'pares: '.$1 if $string =~ $pares;

Clases de carácteres
my $string = '1 ó 2 pajaritos en la fuente';
my $vocals = qr/([aeiou])/;
my $pares = qr/([2468])/;
say 'vocales: '.$1 if $string =~ $vocals;
say 'pares: '.$1 if $string =~ $pares;
> vocales: a
> pares: 2
 
Se muestra la primera vocal que encuentra
No hemos tenido en cuenta la ' ó '

Clases de carácteres
Podemos crear un rango continuo de carácteres en la clase 
mediante el guión ' - '
my $letters = qr/[a-zA-Z]/;
en este caso se buscará coincidencias de cualquier letra ya 
sea mayúscula o minúscula.
Lo mismo podemos hacer con los números:
    my $numbers = qr/[0-9]/;
es decir, 0, 1, 2, 3, 4, 5, 6, 7, 8 y 9

Clases de carácteres
Si queremos utilizar el guión como carácter de búsqueda 
debemos situarlo al principio o al final del patrón:
my $signos = qr/[-!?]/;
my $signos = qr/[!?-]/;
 
o bien escapar el carácter:
my $signos = qr/[!\-?]/; 

Clases de carácteres
Para buscar todo menos la clase de caracteres añadimos ^ al 
principio:
    my $pares = qr/[^2468]/;
 
 o sea, todos los números que no sean pares

Capturando datos
Las regex permiten capturar y agrupar porciones de las 
búsquedas para su uso posterior.
Para ello agrupamos la porción de datos entre paréntesis ()
    my $data = qr/(.+)\s(.+)/;
    say $1.' '.$2;
la captura se almacena en variables mágicas:
    $1 hace referencia al primer grupo
    $2 al segundo grupo

Capturando datos
La captura mediante nombres se añade a partir de perl 5.10
my $string = '[email protected]';
my $name = qr/\A(?<name>\w+[^@])/;
my $domain = qr/@(?<dom>.+)/;
my $email = qr/$name$domain/;
say $+{dom} if $string =~ $email;
say $+{name} if $string =~ $email;
 

Capturando datos
my $string = '[email protected]';
my $name = qr/\A(?<name>\w+[^@])/;
my $domain = qr/@(?<dom>.+)/;
my $email = qr/$name$domain/;
say $+{dom} if $string =~ $email;
say $+{name} if $string =~ $email;
 
> barcelonapm.org
> info
 

Capturando datos
La captura de datos mediante nombre sigue la siguiente 
sintaxis:
    (?<nombre captura> ... regex ...)
 
Cuando se cumple una expresión, perl almacena en la variable 
mágica %+ los datos conseguidos.
En este hash la clave es el nombre de la captura y el valor los 
datos conseguidos.
    $+{nombre_captura}
 

Agrupación y Alternación
Podemos agrupar partes de un patrón mediante paréntesis ()
    qr/perl+/;     <-- puede encontrar perl, perlita, perlero, ...
    qr/(perl)+/;  <-- encontrará perl 
El patrón agrupado dentro de la expresión es almacenado en 
un grupo de captura (parecido a un buffer) y podemos 
reutilizarla en la expresión mediante \1, \2, etc :
    qr/(perl)+\1/; <==> qr/(perl)+(perl)+/;

Agrupación y Alternación
En algunos casos necesitamos que se busque una u otra cosa
Para ello usamos el metacaracter ' | '
    qr/Carlos|Alex|Frankie/;
La comparación será positiva si encuentra cualquiera de los 3 
nombres.
    qr/(Modern|Barroque)+Perl/;
será válido para las cadenas
    Modern Perl
    Barroque Perl

Agrupación y Alternación
Para reducir los riesgos de confusión en las capturas de datos 
podemos utilizar la secuéncia ' ?: ' que indica que el grupo no 
es capturable 
 
    qr/(?:Modern|Barroque)+Perl/;
 
en este caso $1 no tiene valor 

Condiciones
Usamos la secuencia ' ?= ' o ' ?! ' para indicar una condición en 
el patrón de búsqueda.
    my $string_1 = 'catastrofe';
    my $cond_1 = qr/cat(?!astrofe)/;
    my $cond_2 = qr/cat(?=.)/;
    say 'oh no!!!' if $string_1 =~ $cond_1;
    say 'found a cat' if $string_2 =~ $cond_2;

Condiciones
    my $cond_1 = qr/cat(?!astrofe)/;
    my $cond_2 = qr/cat(?=.)/;
    > found a cat
$cond_1 indica que 'cat' no puede ser seguida por 'astrofe', por 
lo que 'catastrofe' es una palabra que no queremos
$cond_2 busca una palabra que empieza por 'cat' y seguida 
por 0 ó cualquier carácter
Las condiciones deben tener un tamaño fijo, no se deben 
utilizar cuantificadores.

Modificadores
Los modificadores cambian el comportamiento de los 
operadores de las expresiones regulares.
Estos modificadores aparecen al final del match, substitucion o 
qr//
Por ejemplo, para ignorar entre mayúsculas y minúsculas 
usamos el modificador ' /i '
    qr=/Perl/i; <== encuentra 'Perl' y 'perl'

Modificadores
Se pueden añadir los modificadores en medio de la regex 
mediante la sentencia ' (?i) ', pero solo para agrupamientos.
    qr=/Modern ((?i)perl)/;
Encontrará tanto 'Modern Perl' como 'Moden perl'
Mientras que /i modifica toda la regex, (?i) solo un grupo
Para desactivar un modificador precedente usamos ' (?-i) '

Modificadores
Otros modificadores:
/m   Trata a la cadena como múltiples líneas. Es decir, cambia 
"^" y "$" de coincidir con el principio y final de cadena para 
coincidir con el principio y final de cualquier línea dentro de la 
cadena.
/s   Trata la cadena como una sola línea. Es decir, cambia "." 
para que coteje con cualquier carácter, incluso el fin de línea, 
que normalmente no lo haría.

Modificadores
Usados juntos, como /ms, hacen que "." coincida con cualquier 
carácter, mientras que "^" y "$" coincidan, respectivamente, 
con justo después y justo antes de los caracteres nueva línea, 
dentro de la cadena.

Modificadores
/i   Hace cotejamientos independientes del tamaño de caja.
Si "use locale" está activo, el tamaño de caja se toma del 
locale actual. Ver perllocale.
/x   Extiende la legibilidad de su patrón permitiendo espacios 
en blanco y comentarios.
/p   Preserva la cadena cotejada en ${^PREMATCH}, $
{^MATCH}, y ${^POSTMATCH}, estando disponibles para ser 
usados después del cotejo.

Modificadores
/g y c  Coincidencia global, y mantenimiento de la posición 
actual después de un cotejamiento fallido. 
 
A diferencia de i, m, s y x, estas dos opciones afectan la forma 
en que la regex es usada, en lugar de a la propio expresión 
regular. 

Coincidencias Inteligentes
El operador inteligente ' ~~ ' compara dos operadores y 
devuelve verdadero si se encuentra una en la otra.
Por ejemplo:
    my $x = 10;
    my $y = 20;
    say 'no es igual' unless $x ~~ $y;
    my $x = 10;
    my $y = '10 puntos';
    say 'numeros coinciden' if $x ~~ $y;

Coincidencias Inteligentes
El tipo de comparación depende primero del tipo de operador 
de la derecha.
 
Si el operador de la derecha es escalar con un componente 
numérico la comparación usará una igualdad numérica.
 
Si el operador de la derecha es un array, la comparación 
realizará un grep
 
Si el operador de la derecha es un hash, la comparación 
buscará la existencia de una o más claves.

Coincidencias Inteligentes
my $needlepat = qr/needle/;
say 'Pattern match'if $needle ~~ $needlepat;
say 'Grep through array' if @haystack ~~ $needlepat;
say 'Grep through hash keys' if %hayhash ~~ $needlepat;
say 'Grep through array'if $needlepat ~~ @haystack;
say 'Array elements exist as hash keys'if %hayhash ~~ @haystack;
say 'Array elements smart match'if @strawstack ~~ @haystack;
say 'Grep through hash keys'if $needlepat ~~ %hayhash;
say 'Array elements exist as hash keys' if @haystack ~~ %hayhach;
say 'Hash keys identical'if %hayhash ~~ %haymap;
más información en perldoc perlsyn

Documentación sobre regex
Disponemos de una gran fuente de información en perldoc:
 
•perldoc perlretut  => Perl Regular Expresions Tutorial
•perldoc perlreref => Perl Regular Expresions Reference
•perldoc perlre      => Perl Regular Expresions

Preguntas?
 

barcelona-pm
(cc) 2011 - cjuan 
http://barcelonapm.wordpress.com/