lunes, 1 de septiembre de 2014

EXPRESIONES REGULARES EN PYTHON(II)

METACARACTERES Y PATRONES
Son símbolos que indican un comportamiento especial como repetición, rango, exclusión o separación.
. ^ $ * + ? { } [ ] \ | ( )

.
Indica cualquier carácter (letras, números, signos de puntuación, espacios) excepto una nueva línea (\n):
>>> re.findall('.', 'Benevolent dictator')
['B', 'e', 'n', 'e', 'v', 'o', 'l', 'e', 'n', 't', ' ', 'd', 'i', 'c', 't', 'a', 't', 'o', 'r']

>>> re.findall('.', 'Benevolent\ndictator') #Ignora la nueva línea (\n)
['B', 'e', 'n', 'e', 'v', 'o', 'l', 'e', 'n', 't', 'd', 'i', 'c', 't', 'a', 't', 'o', 'r']


>>> re.findall('.', 'Benevolent\tdictator') #Pero no ignora la tabulación (\t)
['B', 'e', 'n', 'e', 'v', 'o', 'l', 'e', 'n', 't', '\t', 'd', 'i', 'c', 't', 'a', 't', 'o', 'r']


*
Tiene en cuenta el carácter anterior cero o más veces. Por ejemplo, el patrón "in*o" identifica estas combinaciones: io (ninguna presencia de la "n"), ino (una aparición de la "n"), inno (dos apariciones de la "n").
>>> re.findall('in*o', 'inocencia, innovaciones')
['ino', 'inno', 'io']


+
Indica el carácter anterior una o más veces:
>>> re.findall('in+o', 'inocencia, innovaciones')
['ino', 'inno']


[ ]
Indica que puede haber una coincidencia con cualquier carácter entre los corchetes. También se puede incluir el rango entre los corchetes:
[a-z] : cualquier letra minúscula
[0-9] : cualquier dígito
[a-dA-D] : las letras de la a la d minúsculas o mayúsculas

>>> re.findall('cu[sz]co', 'se puede escribir cusco o cuzco')
['cuzco', 'cusco']

Se puede señalar un rango usando guión. Por ejemplo, [0-9] busca cualquier dígito entre 0 y 9.

>>> re.findall('[0-9]', '3 de enero de 2014')
['3'] # el único con una sola cifra

[^ ]
Busca cualquier caracter excepto el indicado en corchetes

>>> re.findall('est[^a]s', 'estas, estos, estes')
['estos', 'estes']

{ n }
Repite el elemento previo n veces. Se puede definir un rango de coincidencias

{2,4} : de 2 a 4 caracteres siendo el comportamiento "voraz", es decir, primero trata de hacer coincidir cuatro caracteres, luego tres, luego dos.
{2,} : indica dos o más caracteres.

>>> re.findall('[a-z]{3}', 'Django es un framework de desarrollo web')
['jan', 'fra', 'mew', 'ork', 'des', 'arr', 'oll', 'web']

>>> re.findall('[a-z]{3,4}', 'Django es un framework de desarrollo web')
['jang', 'fram', 'ewor', 'desa', 'rrol', 'web']

>>> re.findall('[a-z]{3,}', 'Django es un framework de desarrollo web')
['jango', 'framework', 'desarrollo', 'web']


^ $
Buscan al comienzo y al final de la cadena de texto respectivamente.
>>> re.findall('^Django', 'Django es un framework de desarrollo web')
['Django']

>>> re.findall('^web', 'Django es un framework de desarrollo web')
[]  # 'web' no está al comienzo de la cadena

>>> re.findall('web$', 'Django es un framework de desarrollo web')
['web']  # 'web' está al final de la cadena


?
Busca una o cero coincidencias del caracter anterior.
i?python : busca python o ipython.
>>> re.findall('i?python', 'ipython es iron python')
['ipython', 'python']

\
Permite ignorar caracteres especiales como [], ?, +, etc. Por ejemplo, si queremos analizar operaciones matemáticas debemos ignorar el significado de + y * en el módulo de expresiones regulares:
>>> re.split(' \+ ', '4 + 8') #Queremos extraer sólo los números
['4', '8']

|
Identifica un patrón u otro siendo su comportamiento "no voraz (not greedy)", es decir, al encontrar la coincidencia de la izquierda se detiene. Por ejemplo, queremos sustituir un anglicismo:
>>> re.sub('basket|basketball', 'baloncesto', 'Jugadores de basketball de la liga nacional de basket') #Encuentra basketball y lo sustituye por baloncestoball
'Jugadores de baloncestoball de la liga nacional de baloncesto'

Para corregir este comportamiento simplemente colocamos el más largo primero:
>>> re.sub('basketball|basket', 'baloncesto', 'Jugadores de basketball de la liga nacional de basket')
'Jugadores de baloncesto de la liga nacional de baloncesto'


()
Los paréntesis agrupan expresiones regulares e indican el comienzo y el final de un grupo. Findall agrupa las coincidencias en tuplas:

>>> re.findall(r"(\w+): (\w+)", "nombre: Gabriel, apellido: Marquez, numero: 3")
[('nombre', 'Gabriel'), ('apellido', 'Marquez'), ('numero', '3')]



(?:)

 Agrupa expresiones regulares pero no captura coincidencias. Esto es más evidente al usar split:
>>> re.split(r"(?:\w+):", "nombre: Gabriel, apellido: Marquez, numero: 3")
['', ' Gabriel, ', ' Marquez, ', ' 3']


Comparemos al usar sólo paréntesis:
>>> re.split(r"(\w+):", "nombre: Gabriel, apellido: Marquez, numero: 3")
['', 'nombre', ' Gabriel, ', 'apellido', ' Marquez, ', 'numero', ' 3']


(?P:<>)

Agrupa coincidencias que pueden ser referenciadas por un nombre:
>>> patron = r'(?P<mes>[\d])/(?P<dia>[\d])/(?P<año>[0-9][0-9][0-9][0-9])'
>>> m = re.search(patron, 'nacio en 7/2/1978')

>>> m.group('año')
'1978'
>>> m.group('mes')
'7'
>>> m.group('dia')
'2'

Un ejemplo de la página del tutorial de django:
urlpatterns = [
    # ex: /polls/
    url(r'^$', views.index, name='index'),
    # ex: /polls/5/
    url(r'^(?P[0-9]+)/$', views.detail, name='detail'),
    # ex: /polls/5/results/
    url(r'^(?P[0-9]+)/results/$', views.results, name='results'),
    # ex: /polls/5/vote/
    url(r'^(?P[0-9]+)/vote/$', views.vote, name='vote'),
]

miércoles, 23 de julio de 2014

EXPRESIONES REGULARES EN PYTHON(I)

Las expresiones regulares son como pequeños lenguajes de programación y cuando se trata de procesar cadenas de texto resultan ser herramientas convenientes. Lo primero que hacemos en Python para trabajar con expresiones regulares es invocar al módulo:

>>> import re

Algunas funciones de este módulo son: compile, match, search, findall, split, sub, finditer.

COMPILE
Prepara el patrón de caracteres que se va a buscar. La sintaxis de compile es:

>>> re.compile(pattern, flags=0)

pattern es el patrón de caracteres que se va a buscar y flags es el modificador que cambia el comportamiento del patrón. Esto es lo que hace cada modificador que aplicamos en compile.

FLAGS:
re.IGNORECASE (re.I) no distingue entre mayúsculas y minúsculas.
re.LOCALE (re.L) permite que algunos caracteres especiales tengan en cuenta el idioma que se usa en el computador local.
re.MULTILINE (re.M) permite que "^" busque el comienzo de cada linea (no solo el comienzo del texto) y que "$" busque el final de cada linea (no solo el final del texto).
re.DOTALL (re.S) hace que "." busque cualquier caracter incluyendo una nueva linea (es decir '\n').
re.UNICODE (re.U) permite usar caracteres Unicode.
re.VERBOSE (re.X) se utiliza para poder dividir una expresión regular compleja en pequeños fragmentos que pueden tener comentarios para una mejor comprensión.
Si no se desea compilar pero sí usar modificadores, se puede usar el símbolo (?_) junto con uno o varios modificadores, por ejemplo, (?i), (?m), (?iL).
A parte de la opción de usar modificadores compile ofrece una ligera mayor velocidad de búsqueda de los caracteres correspondientes. Un ejemplo de uso de compile:

>>> pattern = re.compile('python', re.I)
>>> pattern.findall('la programación PyThOn')
['PyThOn']

Aqui con re.I se ignoran las mayúsculas y minúsculas lo que se puede lograr también sin compilar usando (?i):

>>> re.findall('(?i)python','la programacion PyThOn')
['PyThOn']

De otra forma no hay correspondencia:

>>> re.findall('python','la programacion Python')
[]

MATCH
La función match determina si hay una coincidencia únicamente al comienzo del texto procesado:

>>> patron = "Python"
>>> texto1 = "Monty Python"
>>> texto2 = "Python interpreter"
>>> match1 = re.match(patron, texto1)
>>> type(match1)  # no hay coincidencia
<type 'NoneType'>
>>> print match1
None
>>> match2 = re.match(patron, texto2)
<_sre.SRE_Match object at 0x02A2DF00>
>>> match.group() # hay una coincidencia
'Python'

Incluso si se usa el modificador MULTILINE solamente hay búsqueda al comienzo del texto.

>>> texto3 = "Monty \n Python"
>>> match3 = re.match(patron, texto3, re.M)#no hay coincidencia


SEARCH
Busca la primera aparición del patrón de búsqueda en la cadena de texto. Search devuelve un objeto match o None si no hay coincidencia. El método group() devuelve el texto coincidente.

>>> match = re.search('django', 'plataforma django, django reinhardt')
>>> match.group()
'django'

Search sólo devuelve la primera coincidencia. Para comprobarlo podemos usar match.span() que indica dónde comienza y termina el texto encontrado.

>>> match.span()
(11, 17)


FINDALL
Encuentra todas las coincidencias en forma de lista:

>>> re.findall('\d+', '23 de junio, 14 de mayo')
['23', '14']

FINDITER
Devuelve un iterador de objetos match. El resultado es igual a findall pero generando los elementos de la lista uno por uno.

>>> iter = re.finditer('\d+', '23 de junio, 14 de mayo')
>>> iter
<callable-iterator object at 0x02ACE610>
>>> iter.next()
<_sre.SRE_Match object at 0x02AD0528>
>>> iter.next().group()
'14'

SUB
Sustituye el patrón por La sintaxis de sub es:
>>> re.sub(patternreplstringcount=0flags=0)

>>> re.sub('string', 'cadena', 'remplaza la string de caracteres')
'remplaza la cadena de caracteres'

Count indica las veces que se debe sustituir el patrón de caracteres, por defecto se remplazan todas las apariciones del texto.

>>> re.sub('string', 'cadena', 'remplaza la string de caracteres string', count=1)
'remplaza la cadena de caracteres string'

Subn hace lo mismo pero devuelve una tupla con el número de remplazos.

>>> re.subn('string', 'cadena', 'remplaza la string de caracteres string')
('remplaza la cadena de caracteres cadena', 2)

SPLIT
Separa la cadena de texto en donde aparece el patrón.
>>> re.split(patternstringmaxsplit=0flags=0)

>>> re.split('web','Django es un framework web de codigo abierto escrito en Python')
['Django es un framework ', ' de codigo abierto escrito en Python']

sábado, 12 de julio de 2014

Insertar documentos en Mongodb usando Python y pymongo

Mongodb es una base de datos no relacional (NoSQL) que permite la escalabilidad (Big Data) y que ha sido adoptada por empresas reconocidas como Cisco, Codecademy, eBay, Forbes y SAP. 

Pymongo es el driver con el que se puede conectar a Python con Mongodb. Una ventaja de Mongodb es que maneja documentos json equivalentes a diccionarios en Python. Una ejemplo de cómo insertar documentos en la base de datos mongo a través de Python puede ilustrarse usando la página "http://media.mongodb.org/zips.json" que presenta una colección de códigos postales de Estados Unidos del tipo:


{

"_id": "10280",

"city": "NEW YORK",

"state": "NY",

"pop": 5574,

"loc": [

-74.016323,

40.710537

]

}

Los pasos para insertar el documento son los siguientes:



  1. >>> import urllib2
  2. >>> import pymongo
  3. >>> coneccion = pymongo.MongoClient("localhost", 27017)  #Establecemos la                                                                  #conección con mongo
  4. >>> db = coneccion.zipcodes          #La base de datos se llama zipcodes
  5. >>> datos = db.zip                   #La coleccion de documentos se llama zip
  6. >>> url = "http://media.mongodb.org/zips.json"  #De esta página extraemos los                                                                 #datos json
  7. >>> doc = urllib2.urlopen(url)                  #Abrimos la página
  8. >>> for line in doc:
  9.         datos.insert(eval(line))  #Recorremos cada línea, la convertimos en                                                           #diccionario y
  10.                                   #la insertamos en la colección zip


Ahora si entramos a la linea de comados de mongo podemos comprobar que existe la base de datos y la colección. Y podemos usar los comandos de búsqueda de mongodb:

  1. C:\Users>mongo
  2. MongoDB shell version: 2.4.8
  3. connecting to: test
  4. > show dbs
  5. datoszip        0.203125GB
  6. reddit  0.203125GB
  7. test    0.203125GB
  8. > use datoszip
  9. switched to db datoszip
  10. > show collections
  11. system.indexes
  12. zip
  13. > db.zip.findOne()
  14. {
  15.         "_id" : "01001",
  16.         "city" : "AGAWAM",
  17.         "state" : "MA",
  18.         "pop" : 15338,
  19.         "loc" : [
  20.                 -72.622739,
  21.                 42.070206
  22.         ]
  23. }
  24. > db.zip.find({city:'SEATTLE'}).limit(2).pretty()
  25. {
  26.         "_id" : "98101",
  27.         "city" : "SEATTLE",
  28.         "state" : "WA",
  29.         "pop" : 5801,
  30.         "loc" : [
  31.                 -122.330456,
  32.                 47.611435
  33.         ]
  34. }
  35. {
  36.         "_id" : "98102",
  37.         "city" : "SEATTLE",
  38.         "state" : "WA",
  39.         "pop" : 19000,
  40.         "loc" : [
  41.                 -122.320993,
  42.                 47.63025
  43.         ]
  44. }