lunes, 22 de abril de 2013

Expresiones regulares con python tutorial (1/2)

En python existe un modulo llamado re,el cual nos permite realizar regex sobre variables de nuestro script como en muchos otros lenguajes de programación,en python no es la excepción y podemos hacer regex facilmente :D.

Este tutorial lo dividire en dos partes ya que hay varias cuestiones a tratar,pero primero que nada que son las expresiones regulares o regex o patrón:


Una expresión regular, a menudo llamada también patrón, es una expresión que describe un conjunto de cadenas sin enumerar sus elementos. Por ejemplo, el grupo formado por las cadenas Handel, Händel y Haendel se describe mediante el patrón "H(a|ä|ae)ndel". La mayoría de las formalizaciones proporcionan los siguientes constructores: una expresión regular es una forma de representar a los lenguajes regulares (finitos o infinitos) y se construye utilizando caracteres del alfabeto sobre el cual se define el lenguaje.
En informática, las expresiones regulares proveen una manera muy flexible de buscar o reconocer cadenas de texto.

Mas info es.wikipedia.org

Eso dice wikipedia,en mi opinión las expresiones regulares son la forma mas potente y sencilla de buscar texto,existe en muchos lenguajes de programación y también se aplica en lo que es las wildcards de Unix,es algo rara sus sintaxis pero asi debe de ser,ya que por ejemplo le pedimos que busque un texto que comience con H que tenga 2 numeros en medio de la cadena,que no le importe el demas contenido pero que termine en o,suena complicado ordenare eso a la maquina y es complicado,con o sin expresiones regulares,ya que sin expresiones regulares tendriamos que usar infinidad de condicionales anidadas sobre bucles anidados que recorran cada valor de las cadenas por separado :O

Así que hay que dar gracias que existen las regex :D

Tutorial:

Si se preguntan si se puede hacer el ejemplo que dije:

Algo como esto:

Hola 03 Mundo

En regex para buscar esa cadena hacemos esto:

"^H.*\d{2}.*o$"
Se supone que para el final de este tutorial debes entender eso.

Bien en primer lugar debemos importar el modulo re al principio de nuestro script o modulo como sea que le digas:

import re

Abajo del shebang y si nos gusta o necesitamos usar codificación, también abajo de la codificación:

Ahora como sabemos(o si no sabemos) python usa el punto (.) para llamar funciones de los modulos,el modulo re tiene varias funciones pero en esta ocasion nos concentraremos en search(buscar):

re.search()
Adentro de search() le pasamos los parámetros a la función del modulo:


re.search("izquierda","derecha")


en la izquierda tenemos la sintaxis de nuestra expresion regular, y en la derecha la cadena de texto a la cual le vamos a aplicar el comparador de cadena(re.search):

#!/usr/bin/env python3

import re

cadena = "Hola 03 Mundo"

if re.search("^H.*\d{2}.*o$", cadena):
    print ("True")
else:
    print ("False")



En este caso trabajamos con operadores booleanos,si la expresión encuentra lo que busca, es True:


if re.search("^H.*\d{2}.*o$", cadena):

Si no es False,bueno en realidad si no encuentra nada regresa None,pero como usamos un estructura de si o no es 1 o 0 True or False,aunque si gustamos podemos hacer esto:

#!/usr/bin/env python3

import re

cadena = "Hola 03 Mund"

if re.search("^H.*\d{2}.*o$", cadena):
    print ("True")
elif re.search("^H.*\d{2}.*o$", cadena) == None:
    print ("None")
else:
    print ("False")

Esto hará que el 1 y 0 sea if y elif y else sea otra cosa.

re.search no nos sirve solo como comprobador aunque nos funciona muy bien para hacer switching,en un tutorial pasado mostre un sencillo juego de piedra paperl o tijera  en el use un algoritmo sencillo para la eleccion del numero de juegos el cual es asi:

while True:
   n_juegos = input("Numero de juegos : ")
   try:
      int(n_juegos)
      break
   except:
      print("(numeros); ")
      continue


Con regex el algoritmo queda asi y funciona igual:


while True:
   n_juegos = input("Numero de juegos : ")
   if not re.search("\D",n_juegos):
      break
   else:
      print("(numeros); ")
      continue

Como ven se pueden hacer algunas cosas o mejor dicho se pueden hacer las mismas cosas de muchas maneras,en este caso si use re,les dejo el script completo:

Enlace

Bien,entonces porque no use re desde antes?

No fue porque no sabia de su existencia,ni porque no sepa usar expresiones regulares de hecho los perleros somos maestros en las regex ;).Fue porque hay que saber programar y tener un codigo limpio,en ese caso eso se resolvia con un simple try,except y no era necesario llamar un modulo a facilitarnos el trabajo,pero bueno eso depende de nuestro modo de programar:

Izquierda
Izquierda

Como ven la sintaxis de la regex esta a la izquierda,las regex se basan en simbolos especiales los cuales son:

^

Que quiere decir principio de una cadena:

Por ejemplo si buscamos la H en Hola que inicie al principio

re.search("^H","Hola"):
Si no usamos ^ buscara en toda la cadena:

re.search("H","Otro Hola"):

Y en ambos casos es verdadero.

El lado contrario de esto es el símbolo:

$

Este simbolo busca en el final de la cadena:


re.search("H$","Otro Hola"):

En este caso regresa None,ya que seria True si buscáramos a.

Tambien existe el que seria el comodin Unix * (después) el cual busca caracteres después de otro,en este caso para que re de python de el mismo resultado que Unix necesita estar * seguido de un (.) que quiere decir un caracter,por ejemplo:

re.search("...o","Otro Hola"):
Aquí da True porque cada punto es una letra:

O punto (.) 1 caracter de la regex

t punto (.) 2 caracter de la regex

r punto (.) 3 caracter de la regex

o o 4 caracter de la regex

Otro ejemplo:

re.search("..o","Otro Hola"):
Da None porque esta buscando la o donde esta la r.

En el caso de * busca lo que sigue o lo siguiente,antes o despues,sin importar el numero de caracteres:

re.search(".*o","Otro Hola"):

Da True y no es necesario colocal el numero exacto de caracteres,muy util si o estuviera el la posición 1000000 de un texto.

Al igual que en Unix se puede al reves:

re.search("o.*","Otro Hola"):
También da True porque también encuentra la "o" de derecha a izquierda.

Otro simbolo que usaremos en las regex es la (\) este simbolo seguido de una letra en particular quiere decir muchas cosas,por ejemplo en el algoritmo que mostré arriba,en Pseudocódigo es:

si(afirmación) no hay letras en la entrada de la respuesta

Ahora ese algoritmo codificado a python luce así:


if not re.search("\D",respuesta):
Asi que con \D estamos buscando no letras solo numeros,el Pseudocodigo original(texto plano) es:

Pide un numero de juegos, mientras no sea un digito el numero de juegos vuelve a pedir el numero,cuando el numero sea un digito vamos a juegar

Y eso luce asi codificado a python:

while True:
   n_juegos = input("Numero de juegos : ")
   if not re.search("\D",n_juegos):
      break
   else:
      print("(numeros); ")
      continue


En la solución use una negacion lógica porque si usaba una afirmación no daba el resultado que necesitaba,ya que para buscar digitos se usa este simbolo \d solo que tambien recibe las letras,por ejemplo si escribimos:


1ytextoalotontoperousamosunnumeroenmedio


Da True ya que la funcion search busca un numero o una coincidencia en toda la cadena,para que pudiera usar una afirmación tendría que usar la función

match de re

re.match()

Ya que match busca que toda la cadena sea la coincidencia se hubiera podido hacer de esta manera el algoritmo/solucion:


while True:
   n_juegos = input("Numero de juegos : ")
   if re.match("\d",n_juegos):
      break
   else:
      print("(numeros); ")
      continue


Y funciona completamente igual :D

Después vemos match,ahora estos son los caracteres mas importantes:


\d # Se usa para dígitos

\D # Se usa para no digitos

\s # Se usa para espacios en blanco

\S # Se usa para no espacios en blanco espacios

\t # Cualquier tabulador

\w # Cualquier caracter alfanumérico(no símbolos).

\W # No caracteres alfanuméricos (solo simbolos)


De alguna manera el primer algoritmo que deje podria dar problemas por los espacios,asi que podríamos decir:

Que sea un numero y que no tenga espacios



Ya que el usuario podria poner algo como

22 22

Y ese espacio haria que diera errores,asi que se podria hacer esto

if not re.search("\D",n_juegos) and not re.search("\s",n_juegos):

Pero python nos pone todo fácil y ya no es necesario,pero es un ejemplo que puedes llegar a utilizar en otro caso.

Por ultimo en esta parte veremos las llaves {} 


Las llaves se usan para definir un numero de veces que queremos que aparezca algo:


\d{2} digito dos veces
\d{2,4} digitos de dos a cinco veces
\d{4,} digitos cuatro veces o mas

\d{1,3}    digitos de 1 a tres veces
\d{,4}      cuatro digitos o menos

De momento eso es todo,en la próxima parte veremos como compilar nuestro propia variable para usarla como regex y el resto de los simbolos :D.

No hay comentarios.:

Publicar un comentario

Los comentarios serán revisados antes de ser publicados.