Dividir cadenas en palabras con múltiples delimitadores de límites de palabras

Resuelto ooboo asked hace 15 años • 31 respuestas

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?

ooboo avatar Jun 30 '09 00:06 ooboo
Aceptado

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.']
gimel avatar Jun 29 '2009 17:06 gimel

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']
RichieHindle avatar Jun 29 '2009 17:06 RichieHindle

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']
Louis LC avatar Aug 27 '2011 16:08 Louis LC

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 remó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 en A-Z),
  • omite +uno o más delimitadores (podría omitirse gracias a filter(), pero esto produciría innecesariamente cadenas vacías entre separadores de un solo carácter coincidentes),
  • el uso de una cadena sin formator"…" 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 remódulo es mucho más eficiente (en velocidad y concisión) que hacer bucles y pruebas de Python "a mano"!

Eric O. Lebigot avatar May 18 '2014 09:05 Eric O. Lebigot