Uso de expresiones regulares para la manipulación de texto en Python

El preprocesamiento de texto es una de las tareas más importantes en el procesamiento del lenguaje natural (NLP). Por ejemplo, es posible que desee eliminar todos los signos de puntuación del texto...

Introducción

El preprocesamiento de textos es una de las tareas más importantes del Procesamiento natural del lenguaje (PNL). Por ejemplo, es posible que desee eliminar todos los signos de puntuación de los documentos de texto antes de que puedan usarse para la clasificación de texto. De manera similar, es posible que desee extraer números de una cadena de texto. Escribir scripts manuales para tales tareas de preprocesamiento requiere mucho esfuerzo y es propenso a errores. Teniendo en cuenta la importancia de estas tareas de preprocesamiento, las Expresiones regulares (aka Regex) se han desarrollado en diferentes idiomas para facilitar estas tareas de preprocesamiento de texto.

Una expresión regular es una cadena de texto que describe un patrón de búsqueda que se puede usar para hacer coincidir o reemplazar patrones dentro de una cadena con una cantidad mínima de código. En este tutorial, implementaremos diferentes tipos de expresiones regulares en el lenguaje Python.

Para implementar expresiones regulares, se puede usar el paquete re de Python. Importe el paquete re de Python con el siguiente comando:

1
import re

Búsqueda de patrones en una cadena

Una de las tareas más comunes de NLP es buscar si una cadena contiene un patrón determinado o no. Por ejemplo, es posible que desee realizar una operación en la cadena según la condición de que la cadena contenga un número.

Para buscar un patrón dentro de una cadena, se usa la función match y findall del paquete re.

La función de coincidencia

Inicialice una variable texto con una cadena de texto de la siguiente manera:

1
text = "The film Titanic was released in 1998"

Escribamos una expresión regular que coincida con una cadena de cualquier longitud y cualquier carácter:

1
result = re.match(r".*", text)

El primer parámetro de la función match es la expresión regular que desea buscar. La expresión Regex comienza con el alfabeto r seguido del patrón que desea buscar. El patrón debe estar entre comillas simples o dobles como cualquier otra cadena.

La expresión regular anterior coincidirá con la cadena de texto, ya que estamos tratando de hacer coincidir una cadena de cualquier longitud y cualquier carácter. Si se encuentra una coincidencia, la función coincidencia devuelve el objeto _sre.SRE_Match como se muestra a continuación:

1
type(result)

Producción:

1
_sre.SRE_Match

Ahora, para encontrar la cadena coincidente, puede usar el siguiente comando:

1
result.group(0)

Producción:

1
'The film Titanic was released in 1998'

En caso de que la función coincidir no encuentre ninguna coincidencia, se devuelve un objeto nulo.

Ahora la expresión regular anterior coincide con una cadena con cualquier longitud y cualquier carácter. También coincidirá con una cadena vacía de longitud cero. Para probar esto, actualice el valor de la variable de texto con una cadena vacía:

1
text = ""

Ahora, si vuelve a ejecutar la siguiente expresión regular, se encontrará una coincidencia:

1
result = re.match(r".*", text)

Dado que especificamos hacer coincidir la cadena con cualquier longitud y cualquier carácter, incluso se compara una cadena vacía.

Para hacer coincidir una cadena con una longitud de al menos 1, se usa la siguiente expresión regular:

1
result = re.match(r".+", text)

Aquí el signo más especifica que la cadena debe tener al menos un carácter.

Búsqueda de alfabetos

La función coincidencia se puede utilizar para encontrar cualquier letra del alfabeto dentro de una cadena. Vamos a inicializar la variable de texto con el siguiente texto:

1
text = "The film Titanic was released in 1998"

Ahora, para encontrar todas las letras del alfabeto, tanto mayúsculas como minúsculas, podemos usar la siguiente expresión regular:

1
result = re.match(r"[a-zA-z]+", text)

Esta expresión regular establece que la cadena de texto coincide con cualquier alfabeto, desde la a minúscula hasta la z minúscula o la A mayúscula a la Z mayúscula. El signo más especifica que la cadena debe tener al menos un carácter. Imprimamos la coincidencia encontrada por la expresión anterior:

1
print(result.group(0))

Producción:

1
The

En la salida, puede ver que se devuelve la primera palabra, es decir, The. Esto se debe a que la función coincidencia solo devuelve la primera coincidencia encontrada. En la expresión regular, especificamos que se encuentran los patrones con letras mayúsculas y minúsculas desde a hasta z. La primera coincidencia encontrada fue The. Después de la palabra The hay un espacio, que no se trata como una letra del alfabeto, por lo tanto, la coincidencia se detuvo y la expresión devolvió solo The, que es la primera coincidencia.

Sin embargo, hay un problema con esto. Si una cadena comienza con un número en lugar de un alfabeto, la función match devolverá un valor nulo incluso si hay letras después del número. Veamos esto en acción:

1
2
3
text = "1998 was the year when the film titanic was released"
result = re.match(r"[a-zA-z]+", text)
type(result)

Producción:

1
NoneType

En el script anterior, hemos actualizado la variable de texto y ahora comienza con un dígito. Luego usamos la función match para buscar alfabetos en la cadena. Aunque la cadena de texto contiene alfabetos, se devolverá un valor nulo ya que la función match solo coincide con el primer elemento de la cadena.

Para solucionar este problema podemos utilizar la función buscar.

La función de búsqueda

La función buscar es similar a la función coincidir, es decir, intenta hacer coincidir el patrón especificado. Sin embargo, a diferencia de la función coincidir, hace coincidir el patrón globalmente en lugar de hacer coincidir solo el primer elemento. Por lo tanto, la función buscar devolverá una coincidencia incluso si la cadena no contiene un alfabeto al comienzo de la cadena pero contiene un alfabeto en otra parte de la cadena, como se muestra a continuación:

1
2
3
text = "1998 was the year when the film titanic was released"
result = re.search(r"[a-zA-z]+", text)
print(result.group(0))

Producción:

1
was

La función buscar devuelve "era" ya que esta es la primera coincidencia que se encuentra en la cadena de texto.

Cadena coincidente desde el inicio {#cadena coincidente desde el inicio}

Para verificar si una cadena comienza con una palabra específica, puede usar la tecla de zanahoria, es decir, ^ seguida de la palabra para que coincida con la función buscar como se muestra a continuación. Supongamos que tenemos la siguiente cadena:

1
text = "XYZ 1998 was the year when the film titanic was released"

Si queremos averiguar si la cadena comienza con "1998", podemos usar la función buscar de la siguiente manera:

1
2
result = re.search(r"^1998", text)
type(result)

En la salida, se devolverá null ya que la cadena de texto no contiene "1998" directamente al principio.

Ahora cambiemos la variable de texto de contenido y agreguemos "1998" al principio y luego verifiquemos si "1998" se encuentra al principio o no. Ejecute el siguiente script:

1
2
3
4
5
text = "1998 was the year when the film titanic was released"
if re.search(r"^1998", text):
    print("Match found")
else:
    print("Match not found")

Producción:

1
Match found

Coincidencia de cadenas desde el final

Para verificar si una cadena termina con una palabra específica o no, podemos usar la palabra en la expresión regular, seguida del signo de dólar. El signo de dólar marca el final de la declaración. Echa un vistazo al siguiente ejemplo:

1
2
3
4
5
text = "1998 was the year when the film titanic was released"
if re.search(r"1998$", text):
    print("Match found")
else:
    print("Match not found")

En el script anterior, tratamos de encontrar si la cadena de texto termina con "1998", lo cual no es el caso.

Producción:

1
Match not found

Ahora, si actualizamos la cadena y agregamos "1998" al final de la cadena de texto, el script anterior devolverá ‘Coincidencia encontrada' como se muestra a continuación:

1
2
3
4
5
text = "was the year when the film titanic was released 1998"
if re.search(r"1998$", text):
    print("Match found")
else:
    print("Match not found")

Producción:

1
Match found

Sustitución de texto en una cadena

Hasta ahora hemos estado usando expresiones regulares para encontrar si existe un patrón en una cadena. Avancemos con otra función avanzada de expresiones regulares, es decir, sustituir texto en una cadena. La función sub se utiliza para este propósito.

Tomemos un ejemplo simple de la función de sustitución. Supongamos que tenemos la siguiente cadena:

1
text = "The film Pulp Fiction was released in year 1994"

Para reemplazar la cadena "Pulp Fiction" con "Forrest Gump" (otra película lanzada en 1994) podemos usar la función sub de la siguiente manera:

1
result = re.sub(r"Pulp Fiction", "Forrest Gump", text)

El primer parámetro de la función sub es la expresión regular que encuentra el patrón a sustituir. El segundo parámetro es el texto nuevo que desea como reemplazo del texto anterior y el tercer parámetro es la cadena de texto en la que se realizará la operación de sustitución.

Si imprime la variable de resultado, verá la nueva cadena.

Ahora sustituyamos todos los alfabetos de nuestra cadena con el carácter "X". Ejecute el siguiente script:

1
2
3
text = "The film Pulp Fiction was released in year 1994"
result = re.sub(r"[a-z]", "X", text)
print(result)

Producción:

1
TXX XXXX PXXX FXXXXXX XXX XXXXXXXX XX XXXX 1994

Se puede ver en la salida que todos los caracteres han sido reemplazados excepto los mayúsculas. Esto se debe a que solo especificamos a-z y no A-Z. Hay dos formas de resolver este problema. Puede especificar A-Z en la expresión regular junto con a-z de la siguiente manera:

1
result = re.sub(r"[a-zA-Z]", "X", text)

O puede pasar el parámetro adicional flags a la subfunción y establecer su valor en re.I, que se refiere a mayúsculas y minúsculas, de la siguiente manera:

1
result = re.sub(r"[a-z]", "X", text, flags=re.I)

Se pueden encontrar más detalles sobre los diferentes tipos de banderas en Python regex página de documentación oficial.

Clases de caracteres abreviados

Hay diferentes tipos de clases de caracteres abreviados que se pueden usar para realizar una variedad de funciones diferentes de manipulación de cadenas sin tener que escribir una lógica compleja. En esta sección hablaremos de algunos de ellos:

Eliminación de dígitos de una cadena

La expresión regular para encontrar dígitos en una cadena es \d. Este patrón se puede usar para eliminar dígitos de una cadena reemplazándolos con una cadena vacía de longitud cero, como se muestra a continuación:

1
2
3
text = "The film Pulp Fiction was released in year 1994"
result = re.sub(r"\d", "", text)
print(result)

Producción:

1
The film Pulp Fiction was released in year 

Eliminar letras del alfabeto de una cadena

1
2
3
text = "The film Pulp Fiction was released in year 1994"
result = re.sub(r"[a-z]", "", text, flags=re.I)
print(result)

Producción:

1
1994

Eliminación de caracteres de palabras

Si desea eliminar todos los caracteres de palabras (letras y números) de una cadena y conservar los caracteres restantes, puede usar el patrón \w en su expresión regular y reemplazarlo con una cadena vacía de longitud cero, como se muestra a continuación:

1
2
3
text = "The film, '@Pulp Fiction' was ? released in % $ year 1994."
result = re.sub(r"\w","", text, flags = re.I)
print(result)

Producción:

1
, '@ '  ?   % $  .

El resultado muestra que se han eliminado todos los números y letras.

Eliminación de caracteres que no son palabras

Para eliminar todos los caracteres que no son palabras, el patrón \W se puede usar de la siguiente manera:

1
2
3
text = "The film, '@Pulp Fiction' was ? released in % $ year 1994."
result = re.sub(r"\W", "", text, flags=re.I)
print(result)

Producción:

1
ThefilmPulpFictionwasreleasedinyear1994

Desde la salida, puede ver que todo se ha eliminado (incluso los espacios), excepto los números y las letras.

Agrupación de múltiples patrones

Puede agrupar varios patrones para hacer coincidir o sustituir en una cadena usando el corchete. De hecho, hicimos esto cuando emparejamos letras mayúsculas y minúsculas. Agrupemos varios signos de puntuación y eliminémoslos de una cadena:

1
2
3
text = "The film, '@Pulp Fiction' was ? released _ in % $ year 1994."
result = re.sub(r"[,@\'?\.$%_]", "", text, flags=re.I)
print(result)

Producción:

1
The film Pulp Fiction was  released  in   year 1994

Puede ver que la cadena en la variable de texto tenía múltiples signos de puntuación, agrupamos todos estos signos de puntuación en la expresión regular usando corchetes. Es importante mencionar que con un punto y una comilla simple tenemos que usar la secuencia de escape, es decir, una barra inclinada hacia atrás. Esto se debe a que, de manera predeterminada, el operador de punto se usa para cualquier carácter y la comilla simple se usa para indicar una cadena.

Eliminación de varios espacios

A veces, aparecen múltiples espacios entre las palabras como resultado de la eliminación de palabras o puntuación. Por ejemplo, en la salida del último ejemplo, hay varios espacios entre en y año. Estos espacios se pueden eliminar usando el patrón \s, que se refiere a un solo espacio.

1
2
3
text = "The film      Pulp Fiction      was released in   year 1994."
result = re.sub(r"\s+"," ", text, flags = re.I)
print(result)

Producción:

1
The film Pulp Fiction was released in year 1994.

En el script anterior usamos la expresión \s+ que se refiere a espacios únicos o múltiples.

Eliminación de espacios desde el inicio y el final

A veces tenemos una oración que comienza o termina con un espacio, lo que muchas veces no es deseable. El siguiente script elimina los espacios del comienzo de una oración:

1
2
3
text = "         The film Pulp Fiction was released in year 1994"
result = re.sub(r"^\s+", "", text)
print(result)

Producción:

1
The film Pulp Fiction was released in year 1994

De manera similar, para eliminar espacios al final de la cadena, se puede usar el siguiente script:

1
2
3
text = "The film Pulp Fiction was released in year 1994      "
result = re.sub(r"\s+$", "", text)
print(result)

Eliminación de un solo carácter

A veces, eliminar los signos de puntuación, como un apóstrofe, da como resultado un solo carácter que no tiene significado. Por ejemplo, si elimina el apóstrofo de la palabra Jacob's y lo reemplaza con un espacio, la cadena resultante es Jacob s. Aquí la s no tiene sentido. Dichos caracteres individuales se pueden eliminar usando expresiones regulares como se muestra a continuación:

1
2
3
text = "The film Pulp Fiction     s was b released in year 1994"
result = re.sub(r"\s+[a-zA-Z]\s+", " ", text)
print(result)

Producción:

1
The film Pulp Fiction was released in year 1994

El guión reemplaza cualquier letra minúscula o mayúscula entre uno o más espacios, con un solo espacio.

Dividir una cadena

La división de cadenas es otra función muy importante. Las cadenas se pueden dividir usando la función split del paquete re. La función split devuelve una lista de fichas divididas. Dividamos una cadena de palabras donde se encuentran uno o más caracteres de espacio, como se muestra a continuación:

1
2
3
text = "The film      Pulp   Fiction was released in year 1994      "
result = re.split(r"\s+", text)
print(result)

Producción:

1
['The', 'film', 'Pulp', 'Fiction', 'was', 'released', 'in', 'year', '1994', '']

De manera similar, puede usar otras expresiones regulares para dividir una cadena usando las funciones split. Por ejemplo, la siguiente función split divide una cadena de palabras cuando se encuentra una coma:

1
2
3
text = "The film, Pulp Fiction, was released in year 1994"
result = re.split(r"\,", text)
print(result)

Producción:

1
['The film', ' Pulp Fiction', ' was released in year 1994']

Búsqueda de todas las instancias

La función coincidir realiza una coincidencia en el primer elemento, mientras que la función buscar realiza una búsqueda global en la cadena y devuelve la primera instancia coincidente.

Por ejemplo, si tenemos la siguiente cadena:

1
text = "I want to buy a mobile between 200 and 400 euros"

Queremos buscar todos los dígitos de esta cadena. Si usamos la función buscar, solo se devolverá la primera aparición de dígitos, es decir, 200, como se muestra a continuación:

1
2
result = re.search(r"\d+", text)
print(result.group(0))

Producción:

1
200

Por otro lado, la función findall devuelve una lista que contiene todas las declaraciones coincidentes, como se muestra a continuación:

1
2
3
text = "I want to buy a mobile between 200 and 400 euros"
result = re.findall(r"\d+", text)
print(result)

Producción:

1
['200', '400']

Puede ver en la salida que tanto "200" como "400" son devueltos por la función findall.

Conclusión

En este artículo, estudiamos algunas de las funciones de expresiones regulares más utilizadas en Python. Las expresiones regulares son extremadamente útiles para preprocesar texto que se puede usar para una variedad de aplicaciones, como [modelado de temas] (https://en.wikipedia.org/wiki/Topic_model), [clasificación de texto] (https: // en.wikipedia.org/wiki/Document_classification), análisis_de_sentimiento y [resumen de texto](https://en.wikipedia.org/ wiki/Resumen_automático) , etc.