Expresiones regulares
Chema Cortes
ch3m4 en ch3m4.org
Mie Ene 14 12:27:59 CET 2004
Sergi Faber wrote:
> Hola,
>
> Estoy atascado con las expresiones regulares. Estoy empezando a aprender su manejo pero hay un tema concreto en el que no veo la luz. Me interesa extraer todo el texto entre tags de un fichero HTML, pero conservando algunos relativos a la presentación como '<b>', '</b>', '<i>', '</i>', '<cite>', etc. Por ejemplo, si tenemos:
>
> '<p><b>hoy</b> pareces <i>triste</i></p>'
>
> Necesito recuperar:
>
> '<b>hoy</b> pareces <i>triste</i>'
La expresiones regulares son todo un mundo. Me centraré en tu caso para
no extenderme mucho yo también, y sobre todo porque puede resultar
durillo (y es posible que me equivoque :-P).
Como bien hacías, un tag de apertura lo podemos "localizar" así:
<[^/]*?>
un tag de final:
</.*?>
La manera de relacionar ambos como pareja sería utilizando "grupos".
<([^/]*?)>(.*?)</\1>
Particularmente, prefiero los grupos con nombre" (?P<nombre>...) :
<(?P<tag>[^/]*?)>(?P<content>.*?)</(?P=tag)>
Como prueba:
>>> import re
>>> s=re.compile("<(?P<tag>[^/]*?)>(?P<content>.*?)</(?P=tag)>")
>>> texto="<p><b>hoy</b> pareces <i>triste</i></p>"
>>> s.findall(texto)
[('p', '<b>hoy</b> pareces <i>triste</i>')]
Te devuelve los dos grupos que ha encontrado, 'tag' y 'content'
Se podría realizar el proceso otra vez de modo recursivo para ir
obteniendo el resto de tags, o mejor emplear objetos 'match' junto con
el iterador re.finditer para ficheros muy grandes y complejos.
> ¿Hay alguna manera de indicarle que trocee, excepto cuando encuentre los tags que le indico?
No se si está respondida esta pregunta ¿? En cualquier caso, no te
aconsejaría utilizar el re.split para expresiones regulares muy
complejas. Es mejor que controles la disección del texto tú mismo.
> Y ya de paso ¿Se puede indicar en una expresión regular que recupere
TODO un texto menos determinadas palabras? Con [^ab] le indico que no
recupere la 'a' o la 'b' y lo mismo para una secuencia determinada, pero
¿cómo le indico que no recupere 'gato' o 'liebre', por ejemplo?
Se hace también con grupos, empleando el carácter '|' para separar los
distintos grupos de búsqueda. Por ejemplo, para que NO RECUPERE las
palabras 'gato' ó 'liebre':
(?!gato|liebre).*
Si lo pruebas, no resultará como esperabas:
>>> s.findall("gato")
[ 'ato' ]
Para actuar de spliter, quizás lo más simple sea ésto:
>>> s=re.compile("gato\W*|liebre\W*|\W+")
>>> s.split("No quiero ni gato ni liebre en esta frase")
['No', 'quiero', 'ni', '', 'ni', '', 'en', 'esta', 'frase']
Todo ésto se puede complicar mucho más con los búsquedas hacia adelante
y hacia atrás ("look-forward" y "look-behind"):
>>> s=re.compile("(?<!gato|lieb)\W+")
>>> s.split("No me separes ni gato ni lieb en esta frase")
['No', 'me', 'separes', 'ni', 'gato ni', 'lieb en', 'esta', 'frase']
El "look-behind" que empleo (?<...) requiere un pattern de tamaño fijo,
por eso he puesto "lieb", para que coincida en número de letras con "gato".
Siguiendo así, la complicación puede subir exponencialmente. Espero, no
obstante, que con lo dicho te haya resuelto la duda.
--
Res publica non dominetur
------------ próxima parte ------------
_______________________________________________
Python-es mailing list
Python-es en aditel.org
http://listas.aditel.org/listinfo/python-es
Más información sobre la lista de distribución Python-es