Dividir cadenas en palabras con múltiples delimitadores de límites de palabras
Creo que lo que quiero hacer es una tarea bastante común pero no he encontrado ninguna referencia en la web. Tengo texto con puntuación y quiero una lista de palabras.
"Hey, you - what are you doing here!?"
debiera ser
['hey', 'you', 'what', 'are', 'you', 'doing', 'here']
Pero Python str.split()
solo funciona con un argumento, por lo que tengo todas las palabras con puntuación después de dividirlas con espacios en blanco. ¿Algunas ideas?
re.dividir()
re.split(patrón, cadena[, maxsplit=0])
Divida la cadena según las apariciones del patrón. Si se utilizan paréntesis de captura en el patrón, el texto de todos los grupos del patrón también se devuelve como parte de la lista resultante. Si maxsplit es distinto de cero, como máximo se producen divisiones de maxsplit y el resto de la cadena se devuelve como elemento final de la lista. (Nota de incompatibilidad: en la versión original de Python 1.5, se ignoró maxsplit. Esto se solucionó en versiones posteriores).
>>> re.split('\W+', 'Words, words, words.')
['Words', 'words', 'words', '']
>>> re.split('(\W+)', 'Words, words, words.')
['Words', ', ', 'words', ', ', 'words', '.', '']
>>> re.split('\W+', 'Words, words, words.', 1)
['Words', 'words, words.']
Un caso donde las expresiones regulares están justificadas:
import re
DATA = "Hey, you - what are you doing here!?"
print re.findall(r"[\w']+", DATA)
# Prints ['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']
Otra forma rápida de hacer esto sin una expresión regular es reemplazar los caracteres primero, como se muestra a continuación:
>>> 'a;bcd,ef g'.replace(';',' ').replace(',',' ').split()
['a', 'bcd', 'ef', 'g']
Tantas respuestas, pero no puedo encontrar ninguna solución que haga de manera eficiente lo que literalmente pide el título de las preguntas (dividir en múltiples separadores posibles; en cambio, muchas respuestas se dividen en cualquier cosa que no sea una palabra, que es diferente). Así que aquí hay una respuesta a la pregunta del título, que se basa en el re
módulo estándar y eficiente de Python:
>>> import re # Will be splitting on: , <space> - ! ? :
>>> filter(None, re.split(r"[, \-!?:]+", "Hey, you-what are you doing here!?"))
['Hey', 'you', 'what', 'are', 'you', 'doing', 'here']
dónde:
- el
[…]
coincide con uno de los separadores enumerados en el interior, - la
\-
expresión regular está aquí para evitar la interpretación especial de-
como indicador de rango de caracteres (como enA-Z
), - omite
+
uno o más delimitadores (podría omitirse gracias afilter()
, pero esto produciría innecesariamente cadenas vacías entre separadores de un solo carácter coincidentes), - el uso de una cadena sin formato
r"…"
hace explícito que\
la cadena debe mantenerse tal como está (y no introduce un carácter especial); esto es útil para Python 3.12+—, y filter(None, …)
elimina las cadenas vacías posiblemente creadas por los separadores iniciales y finales (ya que las cadenas vacías tienen un valor booleano falso).
Esto re.split()
precisamente "se divide con múltiples separadores", como se solicita en el título de la pregunta.
Además, esta solución es inmune a los problemas con caracteres no ASCII en palabras que se encuentran en algunas otras soluciones (consulte el primer comentario de la respuesta de ghostdog74 ).
¡ El re
módulo es mucho más eficiente (en velocidad y concisión) que hacer bucles y pruebas de Python "a mano"!