¿Cuál es tu aversión a las listas? Son una parte integral del lenguaje, y "" .join (list_of_words) es uno de los modismos principales para hacer una lista de cadenas en una sola cadena delimitada por espacios.
PaulMcG
3
@ Tom / @ Paul: Para cadenas simples, (string) join sería simple y dulce. Pero se vuelve más complejo si hay otro espacio en blanco que uno NO quiere molestar ... en cuyo caso las soluciones "while" o regex serían las mejores. He publicado debajo una unión de cadenas que sería "correcta", con resultados de prueba cronometrados para tres formas de hacerlo.
pythonlarry
Respuestas:
529
>>>import re
>>> re.sub(' +',' ','The quick brown fox')'The quick brown fox'
Esta solución solo maneja caracteres de espacio único. No reemplazaría una pestaña u otros caracteres de espacio en blanco manejados por \ s como en la solución de nsr81.
Taylor Leese
2
Eso es cierto, string.splittambién maneja todo tipo de espacios en blanco.
Josh Lee
66
Prefiero este porque solo se enfoca en el carácter espacial y no afecta a caracteres como '\ n's.
hhsaffar
2
Si claro. Pero antes de esa tira () debe hacerse. Eliminará espacios de ambos extremos.
Hardik Patel
17
Puede usar re.sub(' {2,}', ' ', 'The quick brown fox')para evitar reemplazos redundantes de espacio único con espacio único .
AneesAhmed777
541
foo es tu cadena:
" ".join(foo.split())
Tenga en cuenta que esto elimina "todos los caracteres de espacio en blanco (espacio, tabulación, nueva línea, retorno, avance de página)" (gracias a hhsaffar , ver comentarios). Es decir, "this is \t a test\n"efectivamente terminará como "this is a test".
Tiende a cambiar esa expresión regular para r"\s\s+"que no intente reemplazar espacios ya individuales.
Ben Blank
19
Si quería ese comportamiento, ¿por qué no solo en "\s{2,}"lugar de una solución alternativa para no conocer el comportamiento de expresiones regulares moderadamente avanzado?
Chris Lutz
2
recuerde que sub () no cambia la cadena de entrada s, pero devuelve el nuevo valor.
gcb
1
@moose: es una optimización de legibilidad que una de rendimiento. \s+causaría que la línea lea "reemplazar uno o más espacios con un espacio", en lugar de "reemplazar dos o más espacios con un espacio". Lo primero inmediatamente me hace parar y pensar "¿Por qué reemplazar un espacio con un espacio? Eso es una tontería". Para mí, ese es un olor a código (muy pequeño). En realidad no se puede esperar que haya ninguna diferencia de rendimiento en absoluto entre los dos, ya que va a ser copiado en una nueva cadena de todas formas, y tiene que parar y probar independientemente del lugar donde el espacio está siendo copiado a partir .
Ben Blank
8
Aconsejaría en contra \s\s+porque esto no normalizará un personaje TAB a un espacio normal. un SPACE + TAB se reemplaza de esta manera.
vdboor
51
El uso de expresiones regulares con "\ s" y hacer una cadena simple. Split () también eliminará otros espacios en blanco, como líneas nuevas, retornos de carro, pestañas. A menos que esto se desee, para hacer solo múltiples espacios , presento estos ejemplos.
original_string =''.join(word +(' '* random.randint(1,10))for word in lorem_ipsum.split(' '))
El one-liner esencialmente hará una tira de los espacios iniciales / finales, y conserva un espacio inicial / final (pero solo UNO ;-).
# setup = '''import re
def while_replace(string):while' 'in string:
string = string.replace(' ',' ')return string
def re_replace(string):return re.sub(r' {2,}',' ', string)def proper_join(string):
split_string = string.split(' ')# To account for leading/trailing spaces that would simply be removed
beg =' 'ifnot split_string[0]else''
end =' 'ifnot split_string[-1]else''# versus simply ' '.join(item for item in string.split(' ') if item)return beg +' '.join(item for item in split_string if item)+ end
original_string ="""Lorem ipsum ... no, really, it kept going... malesuada enim feugiat. Integer imperdiet erat."""assert while_replace(original_string)== re_replace(original_string)== proper_join(original_string)#'''
NOTA: La " whileversión" hizo una copia de la original_string, como creo que una vez modificada en la primera ejecución, las ejecuciones sucesivas serían más rápidas (aunque solo sea un poco). Como esto agrega tiempo, agregué esta copia de cadena a las otras dos para que los tiempos mostraran la diferencia solo en la lógica. Tenga en cuenta que las instancias principales stmten timeitsolo se ejecutarán una vez ; De la forma original en que hice esto, el whilebucle funcionó en la misma etiqueta original_string, por lo tanto, en la segunda ejecución, no habría nada que hacer. La forma en que está configurada ahora, llamando a una función, usando dos etiquetas diferentes, eso no es un problema. He agregado assertdeclaraciones a todos los trabajadores para verificar que cambiemos algo cada iteración (para aquellos que puedan tener dudas). Por ejemplo, cambia a esto y se rompe:
Tests run on a laptop with an i5 processor running Windows7(64-bit).
timeit.Timer(stmt = test, setup = setup).repeat(7,1000)
test_string ='The fox jumped over\n\t the log.'# trivialPython2.7.3,32-bit,Windows
test | minum | maximum | average | median
---------------------+------------+------------+------------+-----------
while_replace_test |0.001066|0.001260|0.001128|0.001092
re_replace_test |0.003074|0.003941|0.003357|0.003349
proper_join_test |0.002783|0.004829|0.003554|0.003035Python2.7.3,64-bit,Windows
test | minum | maximum | average | median
---------------------+------------+------------+------------+-----------
while_replace_test |0.001025|0.001079|0.001052|0.001051
re_replace_test |0.003213|0.004512|0.003656|0.003504
proper_join_test |0.002760|0.006361|0.004626|0.004600Python3.2.3,32-bit,Windows
test | minum | maximum | average | median
---------------------+------------+------------+------------+-----------
while_replace_test |0.001350|0.002302|0.001639|0.001357
re_replace_test |0.006797|0.008107|0.007319|0.007440
proper_join_test |0.002863|0.003356|0.003026|0.002975Python3.3.3,64-bit,Windows
test | minum | maximum | average | median
---------------------+------------+------------+------------+-----------
while_replace_test |0.001444|0.001490|0.001460|0.001459
re_replace_test |0.011771|0.012598|0.012082|0.011910
proper_join_test |0.003741|0.005933|0.004341|0.004009
test_string = lorem_ipsum
# Thanks to http://www.lipsum.com/# "Generated 11 paragraphs, 1000 words, 6665 bytes of Lorem Ipsum"Python2.7.3,32-bit
test | minum | maximum | average | median
---------------------+------------+------------+------------+-----------
while_replace_test |0.342602|0.387803|0.359319|0.356284
re_replace_test |0.337571|0.359821|0.348876|0.348006
proper_join_test |0.381654|0.395349|0.388304|0.388193Python2.7.3,64-bit
test | minum | maximum | average | median
---------------------+------------+------------+------------+-----------
while_replace_test |0.227471|0.268340|0.240884|0.236776
re_replace_test |0.301516|0.325730|0.308626|0.307852
proper_join_test |0.358766|0.383736|0.370958|0.371866Python3.2.3,32-bit
test | minum | maximum | average | median
---------------------+------------+------------+------------+-----------
while_replace_test |0.438480|0.463380|0.447953|0.446646
re_replace_test |0.463729|0.490947|0.472496|0.468778
proper_join_test |0.397022|0.427817|0.406612|0.402053Python3.3.3,64-bit
test | minum | maximum | average | median
---------------------+------------+------------+------------+-----------
while_replace_test |0.284495|0.294025|0.288735|0.289153
re_replace_test |0.501351|0.525673|0.511347|0.508467
proper_join_test |0.422011|0.448736|0.436196|0.440318
Para la cadena trivial, parecería que un bucle while es el más rápido, seguido de la división / unión de cadenas Pythonic, y la expresión regular tirando hacia arriba.
Para cadenas no triviales , parece que hay un poco más para considerar. 32 bits 2.7? Es regex al rescate! 2.7 de 64 bits? Un whilebucle es mejor, por un margen decente. 32-bit 3.2, vaya con el "correcto" join. 64 bits 3.3, vaya por un whilebucle. De nuevo.
Al final, uno puede mejorar el rendimiento si / donde / cuando sea necesario , pero siempre es mejor recordar el mantra :
Hubiera preferido si hubiera probado lo simple, ' '.join(the_string.split())ya que este es el caso de uso habitual, pero me gustaría agradecerle por su trabajo.
Mié
@wedi: Según otros comentarios (como de Gumbo ; user984003 , aunque su solución es presuntiva y no funcionará "en todos los casos"), este tipo de solución no cumple con la solicitud del interlocutor. Uno puede usar .split (''), y un comp / gen, pero se vuelve más complicado tratar con espacios iniciales / finales.
pythonlarry
@wedi: Por ejemplo: ' '.join(p for p in s.split(' ') if p)<- todavía perdió espacios iniciales / finales, pero representó múltiples espacios. Para mantenerlos, debe hacer como parts = s.split(' '); (' ' if not parts[0] else '') + ' '.join(p for p in s.split(' ') if p) + (' ' if not parts[-1] else '')!
pythonlarry
Gracias @pythonlarry por el mantra! y me encanta la prueba detallada! Tengo curiosidad por saber si sus pensamientos u opiniones han cambiado sobre esto desde que han pasado 6 años.
JayRizzo
Versión faltante que usa generadores
Lee
42
Tengo que estar de acuerdo con el comentario de Paul McGuire. A mi,
' '.join(the_string.split())
es muy preferible a sacar una expresión regular.
Mis mediciones (Linux y Python 2.5) muestran que dividir y unir es casi cinco veces más rápido que hacer "re.sub (...)", y aún tres veces más rápido si precompila la expresión regular una vez y realiza la operación varias veces. Y es, en cualquier medida, más fácil de entender, mucho más Pythonic.
Esto elimina los espacios finales. Si desea conservarlos, haga: text [0: 1] + "" .join (text [1: -1] .split ()) + text [-1]
user984003
44
Una expresión regular simple es mucho mejor para leer. nunca optimice el rendimiento antes de que lo necesite.
gcb
@gcb: ¿Por qué no? ¿Qué sucede si espera un escenario de alto rendimiento (por ejemplo, debido a la alta demanda)? ¿Por qué no implementar algo que espera que requiera menos recursos desde el principio en ese escenario?
Hassan Baig
1
@HassanBaig si ya tienes el requisito de rendimiento, entonces no es realmente una optimización prematura, ¿verdad? Mi punto es cuando aún no necesita obsesionarse con el rendimiento, siempre es mejor apuntar a la legibilidad.
gcb
14
Similar a las soluciones anteriores, pero más específico: reemplace dos o más espacios con uno:
>>>import re
>>> s ="The fox jumped over the log.">>> re.sub('\s{2,}',' ', s)'The fox jumped over the log.'
También puede usar la técnica de división de cadenas en un Pandas DataFrame sin necesidad de usar .apply (..), que es útil si necesita realizar la operación rápidamente en una gran cantidad de cadenas. Aquí está en una línea:
En algunos casos, es deseable reemplazar las ocurrencias consecutivas de cada carácter de espacio en blanco con una sola instancia de ese carácter. Usaría una expresión regular con referencias posteriores para hacer eso.
(\s)\1{1,}coincide con cualquier carácter de espacio en blanco, seguido de una o más apariciones de ese carácter. Ahora, todo lo que necesita hacer es especificar el primer grupo ( \1) como el reemplazo para el partido.
Envolviendo esto en una función:
import re
def normalize_whitespace(string):return re.sub(r'(\s)\1{1,}', r'\1', string)
>>> normalize_whitespace('The fox jumped over the log.')'The fox jumped over the log.'>>> normalize_whitespace('First line\t\t\t \n\n\nSecond line')'First line\t \nSecond line'
>>>import re
>>> str ='this is a string with multiple spaces and tabs'>>> str = re.sub('[ \t]+',' ', str)>>>print str
this is a string with multiple spaces and tabs
Una línea de código para eliminar todos los espacios adicionales antes, después y dentro de una oración:
sentence =" The fox jumped over the log. "
sentence =' '.join(filter(None,sentence.split(' ')))
Explicación:
Divide toda la cadena en una lista.
Filtrar elementos vacíos de la lista.
Vuelva a unir los elementos restantes * con un solo espacio
* Los elementos restantes deben ser palabras o palabras con signos de puntuación, etc. No probé esto exhaustivamente, pero este debería ser un buen punto de partida. ¡Todo lo mejor!
def unPretty(S):# Given a dictionary, JSON, list, float, int, or even a string...# return a string stripped of CR, LF replaced by space, with multiple spaces reduced to one.return' '.join(str(S).replace('\n',' ').replace('\r','').split())
Lo más rápido que puede obtener para cadenas generadas por el usuario es:
if' 'in text:while' 'in text:
text = text.replace(' ',' ')
El cortocircuito lo hace un poco más rápido que la respuesta integral de pythonlarry . Busque esto si busca eficiencia y busca estrictamente eliminar espacios en blanco adicionales de la variedad de espacio único .
Para eliminar el espacio en blanco, considerando los espacios en blanco iniciales, finales y adicionales entre las palabras, use:
(?<=\s)+|^+(?=\s)|(?=+[\n\0])
El primero ortrata con el espacio en blanco orinicial , el segundo trata con el inicio del espacio en blanco inicial con una cadena y el último trata con el espacio en blanco final.
Como prueba de uso, este enlace le proporcionará una prueba.
Tengo mi método simple que he usado en la universidad.
line ="I have a nice day."
end =1000while end !=0:
line.replace(" "," ")
end -=1
Esto reemplazará cada espacio doble con un solo espacio y lo hará 1000 veces. Significa que puede tener 2000 espacios adicionales y seguirá funcionando. :)
¿En qué se diferencia esto de la respuesta de Anakimi (publicada más de tres años antes)? ¿No es solo una versión más complicada?
Peter Mortensen
0
import re
Text=" You can select below trims for removing white space!! BR Aliakbar "# trims all white spacesprint('Remove all space:',re.sub(r"\s+","",Text), sep='')# trims left spaceprint('Remove leading space:', re.sub(r"^\s+","",Text), sep='')# trims right spaceprint('Remove trailing spaces:', re.sub(r"\s+$","",Text), sep='')# trims bothprint('Remove leading and trailing spaces:', re.sub(r"^\s+|\s+$","",Text), sep='')# replace more than one white space in the string with one white spaceprint('Remove more than one space:',re.sub(' +',' ',Text), sep='')
Resultado:
Eliminar todo el espacio: ¡Puede seleccionar debajo de los bordes para eliminar el espacio en blanco! BRAliakbar Eliminar el espacio inicial: ¡Puede seleccionar los ajustes a continuación para eliminar el espacio en blanco! BR Aliakbar
Eliminar espacios finales: ¡Puede seleccionar los siguientes ajustes para eliminar espacios en blanco! BR Aliakbar Eliminar espacios iniciales y finales: ¡Puede seleccionar los siguientes ajustes para eliminar espacios en blanco! BR Aliakbar Eliminar más de un espacio: ¡Puede seleccionar los siguientes ajustes para eliminar el espacio en blanco! BR Aliakbar
No he leído mucho en los otros ejemplos, pero acabo de crear este método para consolidar múltiples caracteres de espacio consecutivos.
No utiliza ninguna biblioteca, y aunque es relativamente largo en términos de longitud de script, no es una implementación compleja:
def spaceMatcher(command):"""
Function defined to consolidate multiple whitespace characters in
strings to a single space
"""# Initiate index to flag if more than one consecutive character
iteration
space_match =0
space_char =""for char in command:if char ==" ":
space_match +=1
space_char +=" "elif(char !=" ")&(space_match >1):
new_command = command.replace(space_char," ")
space_match =0
space_char =""elif char !=" ":
space_match =0
space_char =""return new_command
command =None
command = str(input("Please enter a command ->"))print(spaceMatcher(command))print(list(spaceMatcher(command)))
Respuestas:
fuente
string.split
también maneja todo tipo de espacios en blanco.re.sub(' {2,}', ' ', 'The quick brown fox')
para evitar reemplazos redundantes de espacio único con espacio único .foo
es tu cadena:Tenga en cuenta que esto elimina "todos los caracteres de espacio en blanco (espacio, tabulación, nueva línea, retorno, avance de página)" (gracias a hhsaffar , ver comentarios). Es decir,
"this is \t a test\n"
efectivamente terminará como"this is a test"
.fuente
o
dado que el espacio antes de la coma se enumera como un motivo favorito en PEP 8 , como lo menciona el usuario Martin Thoma en los comentarios.
fuente
r"\s\s+"
que no intente reemplazar espacios ya individuales."\s{2,}"
lugar de una solución alternativa para no conocer el comportamiento de expresiones regulares moderadamente avanzado?s
, pero devuelve el nuevo valor.\s+
causaría que la línea lea "reemplazar uno o más espacios con un espacio", en lugar de "reemplazar dos o más espacios con un espacio". Lo primero inmediatamente me hace parar y pensar "¿Por qué reemplazar un espacio con un espacio? Eso es una tontería". Para mí, ese es un olor a código (muy pequeño). En realidad no se puede esperar que haya ninguna diferencia de rendimiento en absoluto entre los dos, ya que va a ser copiado en una nueva cadena de todas formas, y tiene que parar y probar independientemente del lugar donde el espacio está siendo copiado a partir .\s\s+
porque esto no normalizará un personaje TAB a un espacio normal. un SPACE + TAB se reemplaza de esta manera.El uso de expresiones regulares con "\ s" y hacer una cadena simple. Split () también eliminará otros espacios en blanco, como líneas nuevas, retornos de carro, pestañas. A menos que esto se desee, para hacer solo múltiples espacios , presento estos ejemplos.
Utilicé 11 párrafos, 1000 palabras, 6665 bytes de Lorem Ipsum para obtener pruebas de tiempo realistas y utilicé espacios adicionales de longitud aleatoria en todo:
El one-liner esencialmente hará una tira de los espacios iniciales / finales, y conserva un espacio inicial / final (pero solo UNO ;-).
NOTA:
La "Tenga en cuenta que las instancias principaleswhile
versión" hizo una copia de laoriginal_string
, como creo que una vez modificada en la primera ejecución, las ejecuciones sucesivas serían más rápidas (aunque solo sea un poco). Como esto agrega tiempo, agregué esta copia de cadena a las otras dos para que los tiempos mostraran la diferencia solo en la lógica.stmt
entimeit
solo se ejecutarán una vez ; De la forma original en que hice esto, elwhile
bucle funcionó en la misma etiquetaoriginal_string
, por lo tanto, en la segunda ejecución, no habría nada que hacer. La forma en que está configurada ahora, llamando a una función, usando dos etiquetas diferentes, eso no es un problema. He agregadoassert
declaraciones a todos los trabajadores para verificar que cambiemos algo cada iteración (para aquellos que puedan tener dudas). Por ejemplo, cambia a esto y se rompe:Para la cadena trivial, parecería que un bucle while es el más rápido, seguido de la división / unión de cadenas Pythonic, y la expresión regular tirando hacia arriba.
Para cadenas no triviales , parece que hay un poco más para considerar. 32 bits 2.7? Es regex al rescate! 2.7 de 64 bits? Un
while
bucle es mejor, por un margen decente. 32-bit 3.2, vaya con el "correcto"join
. 64 bits 3.3, vaya por unwhile
bucle. De nuevo.Al final, uno puede mejorar el rendimiento si / donde / cuando sea necesario , pero siempre es mejor recordar el mantra :
IANAL, YMMV, Caveat Emptor!
fuente
' '.join(the_string.split())
ya que este es el caso de uso habitual, pero me gustaría agradecerle por su trabajo.' '.join(p for p in s.split(' ') if p)
<- todavía perdió espacios iniciales / finales, pero representó múltiples espacios. Para mantenerlos, debe hacer comoparts = s.split(' '); (' ' if not parts[0] else '') + ' '.join(p for p in s.split(' ') if p) + (' ' if not parts[-1] else '')
!Tengo que estar de acuerdo con el comentario de Paul McGuire. A mi,
es muy preferible a sacar una expresión regular.
Mis mediciones (Linux y Python 2.5) muestran que dividir y unir es casi cinco veces más rápido que hacer "re.sub (...)", y aún tres veces más rápido si precompila la expresión regular una vez y realiza la operación varias veces. Y es, en cualquier medida, más fácil de entender, mucho más Pythonic.
fuente
Similar a las soluciones anteriores, pero más específico: reemplace dos o más espacios con uno:
fuente
Una simple almación
fuente
También puede usar la técnica de división de cadenas en un Pandas DataFrame sin necesidad de usar .apply (..), que es útil si necesita realizar la operación rápidamente en una gran cantidad de cadenas. Aquí está en una línea:
fuente
Esto eliminará todas las pestañas, nuevas líneas y múltiples espacios en blanco con un solo espacio en blanco.
fuente
He intentado el siguiente método e incluso funciona con casos extremos como:
Pero si prefiere una expresión regular, puede hacerlo como:
Aunque se debe realizar un preprocesamiento para eliminar el espacio final y final.
fuente
Esto también parece funcionar:
Donde la variable
s
representa tu cadena.fuente
En algunos casos, es deseable reemplazar las ocurrencias consecutivas de cada carácter de espacio en blanco con una sola instancia de ese carácter. Usaría una expresión regular con referencias posteriores para hacer eso.
(\s)\1{1,}
coincide con cualquier carácter de espacio en blanco, seguido de una o más apariciones de ese carácter. Ahora, todo lo que necesita hacer es especificar el primer grupo (\1
) como el reemplazo para el partido.Envolviendo esto en una función:
fuente
Otra alternativa:
fuente
Una línea de código para eliminar todos los espacios adicionales antes, después y dentro de una oración:
Explicación:
* Los elementos restantes deben ser palabras o palabras con signos de puntuación, etc. No probé esto exhaustivamente, pero este debería ser un buen punto de partida. ¡Todo lo mejor!
fuente
Solución para desarrolladores de Python:
Salida:
Original string: Python Exercises Are Challenging Exercises Without extra spaces: Python Exercises Are Challenging Exercises
fuente
fuente
Lo más rápido que puede obtener para cadenas generadas por el usuario es:
El cortocircuito lo hace un poco más rápido que la respuesta integral de pythonlarry . Busque esto si busca eficiencia y busca estrictamente eliminar espacios en blanco adicionales de la variedad de espacio único .
fuente
Muy sorprendente: nadie publicó una función simple que será mucho más rápida que TODAS las demás soluciones publicadas. Aquí va:
fuente
Si está tratando con un espacio en blanco, dividir en Ninguno no incluirá una cadena vacía en el valor devuelto.
5.6.1. Métodos de cadena, str.split ()
fuente
Resultados :
fuente
Para eliminar el espacio en blanco, considerando los espacios en blanco iniciales, finales y adicionales entre las palabras, use:
El primero
or
trata con el espacio en blancoor
inicial , el segundo trata con el inicio del espacio en blanco inicial con una cadena y el último trata con el espacio en blanco final.Como prueba de uso, este enlace le proporcionará una prueba.
https://regex101.com/r/meBYli/4
Esto se debe utilizar con la función re.split .
fuente
Tengo mi método simple que he usado en la universidad.
Esto reemplazará cada espacio doble con un solo espacio y lo hará 1000 veces. Significa que puede tener 2000 espacios adicionales y seguirá funcionando. :)
fuente
Tengo un método simple sin dividir:
fuente
Resultado:
Eliminar todo el espacio: ¡Puede seleccionar debajo de los bordes para eliminar el espacio en blanco! BRAliakbar Eliminar el espacio inicial: ¡Puede seleccionar los ajustes a continuación para eliminar el espacio en blanco! BR Aliakbar
Eliminar espacios finales: ¡Puede seleccionar los siguientes ajustes para eliminar espacios en blanco! BR Aliakbar Eliminar espacios iniciales y finales: ¡Puede seleccionar los siguientes ajustes para eliminar espacios en blanco! BR Aliakbar Eliminar más de un espacio: ¡Puede seleccionar los siguientes ajustes para eliminar el espacio en blanco! BR Aliakbar
fuente
No he leído mucho en los otros ejemplos, pero acabo de crear este método para consolidar múltiples caracteres de espacio consecutivos.
No utiliza ninguna biblioteca, y aunque es relativamente largo en términos de longitud de script, no es una implementación compleja:
fuente