2010-04-26 7 views
16

Una peculiaridad particular de la (por lo demás bastante potente) re módulo en Python es que re.split()will never split a string on a zero-length match, por ejemplo si quiero dividir una cadena a lo largo de los límites de palabra:¿Por qué Python's `re.split()` no se divide en coincidencias de longitud cero?

>>> re.split(r"\s+|\b", "Split along words, preserve punctuation!") 
['Split', 'along', 'words,', 'preserve', 'punctuation!'] 

en lugar de

['', 'Split', 'along', 'words', ',', 'preserve', 'punctuation', '!'] 

¿Por qué tiene esta limitación? ¿Es por diseño? ¿Se comportan así otros sabores regex?

Respuesta

22

Es una decisión de diseño que se tomó, y podría haber ido en cualquier dirección. Tim Peters hizo this post de explicar:

Por ejemplo, si se divide "abc" por el patrón x *, ¿qué esperas? El patrón coincide (con longitud 0) en 4 lugares, pero apuesto a la mayoría de la gente se sorprendería de conseguir

[ '', 'a', 'b', 'c', '']

espalda en lugar de (como lo hacen llegar)

[abc]

Algunos otros están en desacuerdo con él sin embargo. Guido van Rossum doesn't want it changed debido a problemas de compatibilidad con versiones anteriores. Lo hizo say:

Sin embargo, estoy de acuerdo con agregar un indicador para permitir este comportamiento.

Editar:

Hay una workaround publicado por Jan Burgy:

>>> s = "Split along words, preserve punctuation!" 
>>> re.sub(r"\s+|\b", '\f', s).split('\f') 
['', 'Split', 'along', 'words', ',', 'preserve', 'punctuation', '!'] 

Dónde '\f' puede ser sustituido por cualquier carácter no utilizado.

+0

Gracias por los enlaces, de la solución. Realmente creo que deberían tomar la sugerencia de la BDFL y agregar una bandera para esto. –

+0

Esta es una decisión de diseño realmente cojo. Los RE son algo en lo que las decisiones de diseño NO DEBEN ser impulsadas por lo que la gente "espera" porque muchas cosas sobre RE no están en línea con las "expectativas" de las personas, sea lo que sea que eso signifique de todos modos. 'x *' debe coincidir con '' abc'' porque eso es lo que dice el RE: "hacer coincidir una x, cero o más veces". Eso es lo que obtienes cuando usas '*'. –

+0

Acabo de toparme con este problema al intentar dividir un nombre de variable de caso pascal ('re.split ('(? <= [A-z]) (? = [A-Z])', name)'). Demasiado. – Blixt

0

Básicamente, split() es dos funciones diferentes en una. Si proporciona un parámetro, se comporta de manera muy diferente a cuando se llama sin uno.

En primer lugar, sería parece que

s.split() == s.split(' \t\n') 

pero esto no es el caso, como lo han demostrado. El doctor dice:

[...] Si no se especifica SEP o es Ninguno, cualquier cadena de espacios en blanco es un separador y cadenas vacías se eliminan del resultado. [...]

Incluso al agregar un parámetro 'remove_empty' aún se comportaría raro, porque el valor predeterminado 'eliminar_empty' depende de que el parámetro 'sep' esté allí.

+0

Creo que tiene el '.split()' incorrecto - Me refería a 're.split()', no al método de cadena. –

+0

ah, por supuesto :-) –

1

Para solucionar este problema, puede utilizar el modo de la regex package que hace VERSION1split()producen de longitud cero coincide así:

>>> import regex as re 
>>> re.split(r"\s+|\b", "Split along words, preserve punctuation!", flags=re.V1) 
['', 'Split', 'along', 'words', ',', 'preserve', 'punctuation', '!'] 
Cuestiones relacionadas