Para realizar el procesamiento de expresiones regulares en Python, utilizamos el módulo re de la biblioteca estándar. Permite extraer, reemplazar y dividir cadenas utilizando patrones de expresiones regulares.
- re — Regular expression operations — Python 3.10.0 Documentation
- Regular Expression HOWTO — Python 3.10.0 Documentation
En esta sección, explicaremos primero las funciones y métodos del módulo re.
- Compilación de patrones de expresiones regulares:
compile()
- objeto del partido
- Comprueba si el principio de la cadena coincide, extrae:
match()
- Compruebe si hay coincidencias que no se limiten al principio:
search()
- Comprueba si toda la cadena coincide:
fullmatch()
- Obtenga una lista de todas las piezas coincidentes:
findall()
- Obtiene todas las partes coincidentes como un iterador:
finditer()
- Sustituya la pieza correspondiente:
sub()
,subn()
- Dividir cadenas con patrones de expresión regular:
split()
Después, explicaré los metacaracteres (caracteres especiales) y las secuencias especiales de las expresiones regulares que se pueden utilizar en el módulo re. Básicamente, se trata de la sintaxis estándar de las expresiones regulares, pero hay que tener cuidado con la configuración de las banderas (especialmente re.ASCII).
- Metacaracteres de expresiones regulares, secuencias especiales y advertencias en Python
- Fijación de la bandera
- Limitado a caracteres ASCII:
re.ASCII
- No se distingue entre mayúsculas y minúsculas:
re.IGNORECASE
- Haz coincidir el principio y el final de cada línea:
re.MULTILINE
- Especificar varias banderas
- Limitado a caracteres ASCII:
- Partidos codiciosos y no codiciosos
- Compilar el patrón de expresión regular: compile()
- objeto del partido
- Comprueba si el principio de una cadena coincide, extrae: match()
- Busca coincidencias no limitadas al principio, extracto: search()
- Comprueba si la cadena completa coincide: fullmatch()
- Obtener una lista de todas las partes coincidentes: findall()
- Obtener todas las partes coincidentes como un iterador: finditer()
- Sustituir las partes coincidentes: sub(), subn()
- Dividir cadenas con patrones de expresión regular: split()
- Metacaracteres de expresiones regulares, secuencias especiales y advertencias en Python
- Fijación de la bandera
- Partidos codiciosos y no codiciosos
Compilar el patrón de expresión regular: compile()
Hay dos maneras de realizar el procesamiento de expresiones regulares en el módulo re.
Ejecutar con la función
La primera es una función.re.match()
,re.sub()
Existen funciones como éstas para realizar extracciones, sustituciones y otros procesos utilizando patrones de expresiones regulares.
Los detalles de las funciones se describirán más adelante, pero en todas ellas, el primer argumento es la cadena del patrón de expresión regular, seguido de la cadena a procesar y así sucesivamente. Por ejemplo, en re.sub(), que realiza la sustitución, el segundo argumento es la cadena de sustitución, y el tercer argumento es la cadena a procesar.
import re
s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'
m = re.match(r'([a-z]+)@([a-z]+)\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
result = re.sub(r'([a-z]+)@([a-z]+)\.com', 'new-address', s)
print(result)
# new-address, new-address, ccc@zzz.net
Observe que [a-z] en el patrón de expresión regular de este ejemplo significa cualquier carácter de la a a la z (es decir, el alfabeto en minúsculas), y + significa que se repite el patrón anterior (en este caso [a-z]) una o más veces. El [a-z]+ coincide con cualquier cadena que repita uno o más caracteres alfabéticos en minúscula.
. es un carácter meta (un carácter con significado especial) y debe ser escapado con una barra invertida.
Dado que las cadenas de patrones de expresiones regulares suelen utilizar muchas barras invertidas, es conveniente utilizar cadenas en bruto como en el ejemplo.
Se ejecuta en un método de un objeto de patrón de expresión regular
La segunda forma de procesar las expresiones regulares en el módulo re es el método del objeto patrón de expresión regular.
Utilizando re.compile(), puede compilar una cadena de patrón de expresión regular para crear un objeto de patrón de expresión regular.
p = re.compile(r'([a-z]+)@([a-z]+)\.com')
print(p)
# re.compile('([a-z]+)@([a-z]+)\\.com')
print(type(p))
# <class 're.Pattern'>
re.match()
,re.sub()
Por ejemplo, el mismo proceso que estas funciones puede ser ejecutado como métodos match(),sub() de objetos de expresión regular.
m = p.match(s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
result = p.sub('new-address', s)
print(result)
# new-address, new-address, ccc@zzz.net
Todas las funciones de re.xxx() descritas a continuación también se proporcionan como métodos del objeto de expresión regular.
Si está repitiendo un proceso que utiliza el mismo patrón, es más eficiente generar un objeto de expresión regular con re.compile() y utilizarlo por ahí.
En el siguiente código de ejemplo, la función se utiliza sin compilar por comodidad, pero si se quiere utilizar el mismo patrón repetidamente, se recomienda compilarlo previamente y ejecutarlo como un método de un objeto de expresión regular.
objeto del partido
match(), search(), etc. devuelven un objeto coincidente.
s = 'aaa@xxx.com'
m = re.match(r'[a-z]+@[a-z]+\.[a-z]+', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
print(type(m))
# <class 're.Match'>
La cadena y la posición coincidentes se obtienen mediante los siguientes métodos del objeto match.
- Obtenga la ubicación del partido:
start()
,end()
,span()
- Obtiene la cadena coincidente:
group()
- Obtener la cadena de cada grupo:
groups()
print(m.start())
# 0
print(m.end())
# 11
print(m.span())
# (0, 11)
print(m.group())
# aaa@xxx.com
Si se encierra una parte de un patrón de expresión regular en una cadena con paréntesis(), la parte se procesará como un grupo. En este caso, la cadena de la parte que coincide con cada grupo en groups() puede obtenerse como una tupla.
m = re.match(r'([a-z]+)@([a-z]+)\.([a-z]+)', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
print(m.groups())
# ('aaa', 'xxx', 'com')
Comprueba si el principio de una cadena coincide, extrae: match()
match() devuelve un objeto match si el principio de la cadena coincide con el patrón.
Como se ha mencionado anteriormente, el objeto match puede utilizarse para extraer la subcadena coincidente, o simplemente para comprobar si se ha producido una coincidencia.
match() sólo comprobará el principio. Si no hay ninguna cadena coincidente al principio, devuelve None.
s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'
m = re.match(r'[a-z]+@[a-z]+\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
m = re.match(r'[a-z]+@[a-z]+\.net', s)
print(m)
# None
Busca coincidencias no limitadas al principio, extracto: search()
Al igual que match(), devuelve un objeto match si coincide.
Si hay varias partes coincidentes, sólo se devolverá la primera parte coincidente.
s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'
m = re.search(r'[a-z]+@[a-z]+\.net', s)
print(m)
# <re.Match object; span=(26, 37), match='ccc@zzz.net'>
m = re.search(r'[a-z]+@[a-z]+\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
Si desea obtener todas las partes coincidentes, utilice findall() o finditer() como se describe a continuación.
Comprueba si la cadena completa coincide: fullmatch()
Para comprobar si toda la cadena coincide con el patrón de expresión regular, utilice fullmatch(). Esto es útil, por ejemplo, para comprobar si una cadena es válida como dirección de correo electrónico o no.
Si toda la cadena coincide, se devuelve un objeto coincidente.
s = 'aaa@xxx.com'
m = re.fullmatch(r'[a-z]+@[a-z]+\.com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
Si hay partes no coincidentes (sólo coincidencias parciales o ninguna coincidencia), se devuelve Ninguno.
s = '!!!aaa@xxx.com!!!'
m = re.fullmatch(r'[a-z]+@[a-z]+\.com', s)
print(m)
# None
La función fullmatch() se añadió en Python 3.4. Si quiere hacer lo mismo en versiones anteriores, utilice match() y un metacarácter $ de coincidencia al final. Si toda la cadena desde el principio hasta el final no coincide, devuelve None.
s = '!!!aaa@xxx.com!!!'
m = re.match(r'[a-z]+@[a-z]+\.com$', s)
print(m)
# None
Obtener una lista de todas las partes coincidentes: findall()
findall() devuelve una lista de todas las subcadenas coincidentes. Tenga en cuenta que los elementos de la lista no son objetos coincidentes sino cadenas.
s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'
result = re.findall(r'[a-z]+@[a-z]+\.[a-z]+', s)
print(result)
# ['aaa@xxx.com', 'bbb@yyy.com', 'ccc@zzz.net']
El número de partes coincidentes puede comprobarse mediante la función incorporada len(), que devuelve el número de elementos de la lista.
print(len(result))
# 3
La agrupación con paréntesis() en un patrón de expresión regular devuelve una lista de tuplas cuyos elementos son las cadenas de cada grupo. Esto es equivalente a groups() en el objeto match.
result = re.findall(r'([a-z]+)@([a-z]+)\.([a-z]+)', s)
print(result)
# [('aaa', 'xxx', 'com'), ('bbb', 'yyy', 'com'), ('ccc', 'zzz', 'net')]
Los paréntesis de grupo () pueden anidarse, por lo que si quiere obtener también la coincidencia completa, basta con encerrar toda la coincidencia entre paréntesis ().
result = re.findall(r'(([a-z]+)@([a-z]+)\.([a-z]+))', s)
print(result)
# [('aaa@xxx.com', 'aaa', 'xxx', 'com'), ('bbb@yyy.com', 'bbb', 'yyy', 'com'), ('ccc@zzz.net', 'ccc', 'zzz', 'net')]
Si no se encuentra ninguna coincidencia, se devuelve una tupla vacía.
result = re.findall('[0-9]+', s)
print(result)
# []
Obtener todas las partes coincidentes como un iterador: finditer()
finditer() devuelve todas las partes coincidentes como un iterador. Los elementos no son cadenas como findall(), sino objetos coincidentes, por lo que se puede obtener la posición (índice) de las partes coincidentes.
El propio iterador no puede imprimirse con print() para obtener su contenido. Si se utiliza la función incorporada next() o la sentencia for, se puede obtener el contenido uno a uno.
s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'
result = re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s)
print(result)
# <callable_iterator object at 0x10b0efa90>
print(type(result))
# <class 'callable_iterator'>
for m in result:
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
# <re.Match object; span=(13, 24), match='bbb@yyy.com'>
# <re.Match object; span=(26, 37), match='ccc@zzz.net'>
También se puede convertir en una lista con list().
l = list(re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s))
print(l)
# [<re.Match object; span=(0, 11), match='aaa@xxx.com'>, <re.Match object; span=(13, 24), match='bbb@yyy.com'>, <re.Match object; span=(26, 37), match='ccc@zzz.net'>]
print(l[0])
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
print(type(l[0]))
# <class 're.Match'>
print(l[0].span())
# (0, 11)
Si desea obtener la posición de todas las partes coincidentes, la notación de comprensión de la lista es más conveniente que list().
print([m.span() for m in re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s)])
# [(0, 11), (13, 24), (26, 37)]
El iterador extrae los elementos en orden. Ten en cuenta que si intentas extraer más elementos después de llegar al final, te quedarás sin nada.
result = re.finditer(r'[a-z]+@[a-z]+\.[a-z]+', s)
for m in result:
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
# <re.Match object; span=(13, 24), match='bbb@yyy.com'>
# <re.Match object; span=(26, 37), match='ccc@zzz.net'>
print(list(result))
# []
Sustituir las partes coincidentes: sub(), subn()
Utilizando sub(), puede sustituir la parte coincidente por otra cadena. Se devolverá la cadena sustituida.
s = 'aaa@xxx.com, bbb@yyy.com, ccc@zzz.net'
result = re.sub(r'[a-z]+@[a-z]+\.com', 'new-address', s)
print(result)
# new-address, new-address, ccc@zzz.net
print(type(result))
# <class 'str'>
Cuando se agrupa con parentheses(), la cadena coincidente se puede utilizar en la cadena reemplazada.
Por defecto, se admite lo siguiente: Tenga en cuenta que para las cadenas normales que no son cadenas crudas, se debe enumerar una barra invertida antes de la barra invertida para escapar la barra invertida.
\1 | El primer paréntesis |
\2 | El segundo paréntesis |
\3 | El tercer paréntesis |
result = re.sub(r'([a-z]+)@([a-z]+)\.com', r'\1@\2.net', s)
print(result)
# aaa@xxx.net, bbb@yyy.net, ccc@zzz.net
?P<xxx>
Si nombra el grupo escribiéndolo al principio de los paréntesis del patrón de expresión regular, puede especificarlo utilizando el nombre en lugar del número, como se muestra a continuación.\g<xxx>
result = re.sub(r'(?P<local>[a-z]+)@(?P<SLD>[a-z]+)\.com', r'\g<local>@\g<SLD>.net', s)
print(result)
# aaa@xxx.net, bbb@yyy.net, ccc@zzz.net
El argumento count especifica el número máximo de sustituciones. Sólo se reemplazará el recuento del lado izquierdo.
result = re.sub(r'[a-z]+@[a-z]+\.com', 'new-address', s, count=1)
print(result)
# new-address, bbb@yyy.com, ccc@zzz.net
subn() devuelve una tupla de la cadena sustituida (igual que el valor de retorno de sub()) y el número de partes sustituidas (el número que coincide con el patrón).
result = re.subn(r'[a-z]+@[a-z]+\.com', 'new-address', s)
print(result)
# ('new-address, new-address, ccc@zzz.net', 2)
El método para especificar los argumentos es el mismo que el de sub(). Puede utilizar la parte agrupada por paréntesis, o especificar el número de argumentos.
result = re.subn(r'(?P<local>[a-z]+)@(?P<SLD>[a-z]+)\.com', r'\g<local>@\g<SLD>.net', s)
print(result)
# ('aaa@xxx.net, bbb@yyy.net, ccc@zzz.net', 2)
result = re.subn(r'[a-z]+@[a-z]+\.com', 'new-address', s, count=1)
print(result)
# ('new-address, bbb@yyy.com, ccc@zzz.net', 1)
Dividir cadenas con patrones de expresión regular: split()
split() divide la cadena en la parte que coincide con el patrón, y la devuelve como una lista.
Tenga en cuenta que la primera y la última coincidencia contendrán cadenas vacías al principio y al final de la lista resultante.
s = '111aaa222bbb333'
result = re.split('[a-z]+', s)
print(result)
# ['111', '222', '333']
result = re.split('[0-9]+', s)
print(result)
# ['', 'aaa', 'bbb', '']
El argumento maxsplit especifica el número máximo de divisiones (piezas). Sólo se dividirá la cuenta del lado izquierdo.
result = re.split('[a-z]+', s, 1)
print(result)
# ['111', '222bbb333']
Metacaracteres de expresiones regulares, secuencias especiales y advertencias en Python
Los principales metacaracteres (caracteres especiales) de las expresiones regulares y las secuencias especiales que se pueden utilizar en el módulo re de Python 3 son los siguientes
metacaracteres | contenidos |
---|---|
. | Cualquier carácter que no sea una nueva línea (incluyendo una nueva línea con la bandera DOTALL) |
^ | El principio de la cadena (también coincide con el principio de cada línea con la bandera MULTILINE) |
$ | El final de la cadena (también coincide con el final de cada línea con la bandera MULTILINE) |
* | Repite el patrón anterior más de 0 veces |
+ | Repite el patrón anterior al menos una vez. |
? | Repite el patrón anterior 0 o 1 veces |
{m} | Repite el patrón anterior m veces |
{m, n} | El último patrón.m ~n Repita |
[] | Un conjunto de caracteres[] Coincide con cualquiera de estos caracteres |
| | OA|B Coincide con el patrón A o B |
secuencia especial | contenidos |
---|---|
\d | Números decimales Unicode (limitados a números ASCII por la bandera ASCII) |
\D | \d Es decir, lo contrario de esto. |
\s | Caracteres de espacio en blanco Unicode (limitados a los caracteres de espacio en blanco ASCII por la bandera ASCII) |
\S | \s Es decir, lo contrario de esto. |
\w | Caracteres de palabra Unicode y guiones bajos (limitados a caracteres alfanuméricos ASCII y guiones bajos por la bandera ASCII) |
\W | \w Es decir, lo contrario de esto. |
No todos aparecen en esta tabla. Consulte la documentación oficial para obtener una lista completa.
Tenga en cuenta también que algunos de los significados son diferentes en Python 2.
Fijación de la bandera
Como se muestra en la tabla anterior, algunos metacaracteres y secuencias especiales cambian su modo en función de la bandera.
Aquí sólo se cubren las principales banderas. Consulte la documentación oficial para el resto.
Limitado a caracteres ASCII: re.ASCII
\w
Esto también coincidirá con kanji de doble byte, caracteres alfanuméricos, etc. por defecto para las cadenas de Python 3. No es equivalente a lo siguiente porque no es una expresión regular estándar.[a-zA-Z0-9_]
m = re.match(r'\w+', '漢字ABC123')
print(m)
# <re.Match object; span=(0, 11), match='漢字ABC123'>
m = re.match('[a-zA-Z0-9_]+', '漢字ABC123')
print(m)
# None
Si especifica re.ASCII para las banderas de argumentos en cada función, o añade la siguiente bandera en línea al principio de la cadena de patrones de expresión regular, sólo coincidirá con caracteres ASCII (no coincidirá con japoneses de doble byte, caracteres alfanuméricos, etc.).(?a)
En este caso, los dos siguientes son equivalentes.\w
=[a-zA-Z0-9_]
m = re.match(r'\w+', '漢字ABC123', flags=re.ASCII)
print(m)
# None
m = re.match(r'(?a)\w+', '漢字ABC123')
print(m)
# None
Lo mismo se aplica cuando se compila con re.compile(). Utilice el argumento flags o inline flags.
p = re.compile(r'\w+', flags=re.ASCII)
print(p)
# re.compile('\\w+', re.ASCII)
print(p.match('漢字ABC123'))
# None
p = re.compile(r'(?a)\w+')
print(p)
# re.compile('(?a)\\w+', re.ASCII)
print(p.match('漢字ABC123'))
# None
ASCII también está disponible como la forma corta re. A. Se puede utilizar cualquiera de las dos.
print(re.ASCII is re.A)
# True
\W, lo contrario de \W, también se ve afectado por re.ASCII y las banderas en línea.
m = re.match(r'\W+', '漢字ABC123')
print(m)
# None
m = re.match(r'\W+', '漢字ABC123', flags=re.ASCII)
print(m)
# <re.Match object; span=(0, 11), match='漢字ABC123'>
Al igual que con \w, las dos siguientes coinciden por defecto con caracteres de un solo byte y de dos bytes, pero se limitan a caracteres de un solo byte si se especifican las banderas re.ASCII o inline.
- Combinar los números
\d
- Coincide con un espacio en blanco
\s
- Coincide con los no-números
\D
- Coincide con cualquier espacio que no sea.
\S
m = re.match(r'\d+', '123')
print(m)
# <re.Match object; span=(0, 3), match='123'>
m = re.match(r'\d+', '123')
print(m)
# <re.Match object; span=(0, 3), match='123'>
m = re.match(r'\d+', '123', flags=re.ASCII)
print(m)
# <re.Match object; span=(0, 3), match='123'>
m = re.match(r'\d+', '123', flags=re.ASCII)
print(m)
# None
m = re.match(r'\s+', ' ') # full-width space
print(m)
# <re.Match object; span=(0, 1), match='\u3000'>
m = re.match(r'\s+', ' ', flags=re.ASCII)
print(m)
# None
No se distingue entre mayúsculas y minúsculas:re.IGNORECASE
Por defecto, distingue entre mayúsculas y minúsculas. Para que coincida con ambas, debe incluir tanto las mayúsculas como las minúsculas en el patrón.
re.IGNORECASE
Si se especifica esto, coincidirá con las mayúsculas y minúsculas. Equivale a la bandera i en las expresiones regulares estándar.
m = re.match('[a-zA-Z]+', 'abcABC')
print(m)
# <re.Match object; span=(0, 6), match='abcABC'>
m = re.match('[a-z]+', 'abcABC', flags=re.IGNORECASE)
print(m)
# <re.Match object; span=(0, 6), match='abcABC'>
m = re.match('[A-Z]+', 'abcABC', flags=re.IGNORECASE)
print(m)
# <re.Match object; span=(0, 6), match='abcABC'>
Se puede utilizar menos o igual que.
- bandera en línea
(?i)
- abreviatura
re.I
Haz coincidir el principio y el final de cada línea:re.MULTILINE
^
Los metacaracteres de esta expresión regular coinciden con el principio de la cadena.
Por defecto, sólo se compara el principio de toda la cadena, pero lo siguiente también coincide con el principio de cada línea. Equivale a la bandera m en las expresiones regulares estándar.re.MULTILINE
s = '''aaa-xxx
bbb-yyy
ccc-zzz'''
print(s)
# aaa-xxx
# bbb-yyy
# ccc-zzz
result = re.findall('[a-z]+', s)
print(result)
# ['aaa', 'xxx', 'bbb', 'yyy', 'ccc', 'zzz']
result = re.findall('^[a-z]+', s)
print(result)
# ['aaa']
result = re.findall('^[a-z]+', s, flags=re.MULTILINE)
print(result)
# ['aaa', 'bbb', 'ccc']
$
Coincide con el final de la cadena. Por defecto, sólo se busca el final de toda la cadena.re.MULTILINE
Si lo especifica, también coincidirá con el final de cada línea.
result = re.findall('[a-z]+$', s)
print(result)
# ['zzz']
result = re.findall('[a-z]+$', s, flags=re.MULTILINE)
print(result)
# ['xxx', 'yyy', 'zzz']
Se puede utilizar menos o igual que.
- bandera en línea
(?m)
- abreviatura
re.M
Especificar varias banderas
|
Si desea activar varias banderas al mismo tiempo, utilice esto. En el caso de las banderas en línea, cada carácter debe ir seguido de una letra, como se muestra a continuación.(?am)
s = '''aaa-xxx
漢漢漢-字字字
bbb-zzz'''
print(s)
# aaa-xxx
# 漢漢漢-字字字
# bbb-zzz
result = re.findall(r'^\w+', s, flags=re.M)
print(result)
# ['aaa', '漢漢漢', 'bbb']
result = re.findall(r'^\w+', s, flags=re.M | re.A)
print(result)
# ['aaa', 'bbb']
result = re.findall(r'(?am)^\w+', s)
print(result)
# ['aaa', 'bbb']
Partidos codiciosos y no codiciosos
Este es un problema general con las expresiones regulares, no sólo un problema con Python, pero voy a escribir sobre él porque tiende a meterme en problemas.
Por defecto, lo siguiente es una coincidencia codiciosa, que coincide con la cadena más larga posible.
*
+
?
s = 'aaa@xxx.com, bbb@yyy.com'
m = re.match(r'.+com', s)
print(m)
# <re.Match object; span=(0, 24), match='aaa@xxx.com, bbb@yyy.com'>
print(m.group())
# aaa@xxx.com, bbb@yyy.com
El ? que le sigue dará como resultado una coincidencia mínima y no codiciosa, que coincidirá con la cadena más corta posible.
*?
+?
??
m = re.match(r'.+?com', s)
print(m)
# <re.Match object; span=(0, 11), match='aaa@xxx.com'>
print(m.group())
# aaa@xxx.com
Tenga en cuenta que la coincidencia codiciosa por defecto puede coincidir con cadenas inesperadas.