Supongamos que esta cadena:
The fox jumped over the log.
Transformándose en:
The fox jumped over the log.
¿Cuál es el más simple (1-2 líneas) para lograr esto, sin dividir y entrar en listas?
Supongamos que esta cadena:
The fox jumped over the log.
Transformándose en:
The fox jumped over the log.
¿Cuál es el más simple (1-2 líneas) para lograr esto, sin dividir y entrar en listas?
Respuestas:
>>> import re
>>> re.sub(' +', ' ', 'The quick brown fox')
'The quick brown fox'
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:
" ".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"
.
import re
s = "The fox jumped over the log."
re.sub("\s\s+" , " ", s)
o
re.sub("\s\s+", " ", s)
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.
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:
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 = ' ' if not split_string[ 0] else ''
end = ' ' if not 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)
#'''
# while_replace_test
new_string = original_string[:]
new_string = while_replace(new_string)
assert new_string != original_string
# re_replace_test
new_string = original_string[:]
new_string = re_replace(new_string)
assert new_string != original_string
# proper_join_test
new_string = original_string[:]
new_string = proper_join(new_string)
assert new_string != original_string
NOTA: La " Tenga en cuenta que las instancias principales while
versió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. stmt
en timeit
solo se ejecutarán una vez ; De la forma original en que hice esto, el while
bucle 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 assert
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:
# while_replace_test
new_string = original_string[:]
new_string = while_replace(new_string)
assert new_string != original_string # will break the 2nd iteration
while ' ' in original_string:
original_string = original_string.replace(' ', ' ')
Tests run on a laptop with an i5 processor running Windows 7 (64-bit).
timeit.Timer(stmt = test, setup = setup).repeat(7, 1000)
test_string = 'The fox jumped over\n\t the log.' # trivial
Python 2.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.003035
Python 2.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.004600
Python 3.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.002975
Python 3.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"
Python 2.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.388193
Python 2.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.371866
Python 3.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.402053
Python 3.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 while
bucle es mejor, por un margen decente. 32-bit 3.2, vaya con el "correcto" join
. 64 bits 3.3, vaya por un while
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!
' '.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 como parts = 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,
' '.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.
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:
df['message'] = (df['message'].str.split()).str.join(' ')
import re
string = re.sub('[ \t\n]+', ' ', 'The quick brown \n\n \t fox')
Esto eliminará todas las pestañas, nuevas líneas y múltiples espacios en blanco con un solo espacio en blanco.
He intentado el siguiente método e incluso funciona con casos extremos como:
str1=' I live on earth '
' '.join(str1.split())
Pero si prefiere una expresión regular, puede hacerlo como:
re.sub('\s+', ' ', str1)
Aunque se debe realizar un preprocesamiento para eliminar el espacio final y final.
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'
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:
* 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!
Solución para desarrolladores de Python:
import re
text1 = 'Python Exercises Are Challenging Exercises'
print("Original string: ", text1)
print("Without extra spaces: ", re.sub(' +', ' ', text1))
Salida:
Original string: Python Exercises Are Challenging Exercises
Without extra spaces: Python Exercises Are Challenging Exercises
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 .
Muy sorprendente: nadie publicó una función simple que será mucho más rápida que TODAS las demás soluciones publicadas. Aquí va:
def compactSpaces(s):
os = ""
for c in s:
if c != " " or os[-1] != " ":
os += c
return os
Si está tratando con un espacio en blanco, dividir en Ninguno no incluirá una cadena vacía en el valor devuelto.
string = 'This is a string full of spaces and taps'
string = string.split(' ')
while '' in string:
string.remove('')
string = ' '.join(string)
print(string)
Resultados :
Esta es una cadena llena de espacios y grifos
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 or
trata con el espacio en blanco or
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 .
Tengo mi método simple que he usado en la universidad.
line = "I have a nice day."
end = 1000
while 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. :)
Tengo un método simple sin dividir:
a = "Lorem Ipsum Darum Diesrum!"
while True:
count = a.find(" ")
if count > 0:
a = a.replace(" ", " ")
count = a.find(" ")
continue
else:
break
print(a)
import re
Text = " You can select below trims for removing white space!! BR Aliakbar "
# trims all white spaces
print('Remove all space:',re.sub(r"\s+", "", Text), sep='')
# trims left space
print('Remove leading space:', re.sub(r"^\s+", "", Text), sep='')
# trims right space
print('Remove trailing spaces:', re.sub(r"\s+$", "", Text), sep='')
# trims both
print('Remove leading and trailing spaces:', re.sub(r"^\s+|\s+$", "", Text), sep='')
# replace more than one white space in the string with one white space
print('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)))