Suponha que esta sequência:
The fox jumped over the log.
Transformando em:
The fox jumped over the log.
Qual é a mais simples (1-2 linhas) para conseguir isso, sem dividir e entrar em listas?
Suponha que esta sequência:
The fox jumped over the log.
Transformando em:
The fox jumped over the log.
Qual é a mais simples (1-2 linhas) para conseguir isso, sem dividir e entrar em listas?
Respostas:
>>> import re
>>> re.sub(' +', ' ', 'The quick brown fox')
'The quick brown fox'
string.split
também lida com todos os tipos de espaços em branco.
re.sub(' {2,}', ' ', 'The quick brown fox')
para impedir substituições redundantes de espaço único por espaço único .
foo
é sua string:
" ".join(foo.split())
Esteja avisado, porém isso remove "todos os caracteres de espaço em branco (espaço, guia, nova linha, retorno, alimentação de formulário )" (graças a hhsaffar , consulte os comentários). Ou seja, "this is \t a test\n"
vai acabar efetivamente como "this is a test"
.
import re
s = "The fox jumped over the log."
re.sub("\s\s+" , " ", s)
ou
re.sub("\s\s+", " ", s)
já que o espaço antes da vírgula é listado como uma irritação no PEP 8 , conforme mencionado pelo usuário Martin Thoma nos comentários.
r"\s\s+"
que ele não tente substituir espaços já únicos.
"\s{2,}"
uma solução alternativa para não conhecer o comportamento regex moderadamente avançado?
s
, mas retorna o novo valor.
\s+
faria com que a linha lesse "substitua um ou mais espaços por um espaço", em vez de "substitua dois ou mais espaços por um espaço". O primeiro imediatamente me faz parar e pensar: "Por que substituir um espaço por um espaço? Isso é bobagem". Para mim, isso é um cheiro de código (muito pequeno). Na verdade, eu não esperaria que haja qualquer diferença de desempenho em tudo entre os dois, como ele vai ser copiar para uma nova seqüência de qualquer maneira, e tem que parar e teste independentemente de onde o espaço está sendo copiado a partir .
\s\s+
porque isso não normaliza um caractere TAB de volta para um espaço normal. um SPACE + TAB é substituído dessa maneira.
O uso de expressões regulares com "\ s" e a execução simples de string.split () também removerão outros espaços em branco - como novas linhas, retornos de carro, guias. A menos que isso seja desejado, para fazer apenas vários espaços , apresento esses exemplos.
Usei 11 parágrafos, 1000 palavras e 6665 bytes de Lorem Ipsum para obter testes de tempo realísticos e usei espaços extras de tamanho aleatório em todo:
original_string = ''.join(word + (' ' * random.randint(1, 10)) for word in lorem_ipsum.split(' '))
O one-liner essencialmente faz uma faixa de qualquer espaço à esquerda / à direita e preserva um espaço à frente / à direita (mas apenas UM ;-).
# 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: A " Tenha em mente que o principal while
versão" fez uma cópia do original_string
, como acredito que uma vez modificado na primeira execução, as execuções sucessivas seriam mais rápidas (mesmo que apenas um pouco). À medida que isso aumenta o tempo, adicionei essa cópia de cadeia às outras duas, para que os horários mostrassem a diferença apenas na lógica. stmt
em timeit
casos só será executada uma vez ; da maneira original que eu fiz isso, o while
loop funcionou no mesmo rótulo original_string
, portanto, na segunda execução, não havia nada a fazer. A maneira como está configurada agora, chamando uma função, usando dois rótulos diferentes, isso não é um problema. Adicionei assert
declarações a todos os trabalhadores para verificar se alteramos algo a cada iteração (para aqueles que podem ter dúvidas). Por exemplo, mude para isso e ele quebra:
# 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 a string trivial, parece que um loop while é o mais rápido, seguido pela divisão / junção de cordas Pythonic e pelo regex puxando a traseira.
Para strings não triviais , parece que há um pouco mais a considerar. 32 bits 2.7? É regex para o resgate! 2,7 64 bits? Um while
loop é melhor, por uma margem decente. 32 bits 3.2, vá com o "adequado" join
. 64 bits 3.3, vá para um while
loop. Novamente.
No final, pode-se melhorar o desempenho se / onde / quando necessário , mas é sempre melhor lembrar o mantra :
IANAL, YMMV, Advertência Emptor!
' '.join(the_string.split())
pois esse é o caso de uso usual, mas eu gostaria de agradecer pelo seu trabalho!
' '.join(p for p in s.split(' ') if p)
<- ainda perdemos espaços de avanço / fuga, mas foram responsáveis por vários espaços. Para mantê-los, deve fazer o mesmo parts = s.split(' '); (' ' if not parts[0] else '') + ' '.join(p for p in s.split(' ') if p) + (' ' if not parts[-1] else '')
!
Eu tenho que concordar com o comentário de Paul McGuire. Para mim,
' '.join(the_string.split())
é muito preferível a sacar um regex.
Minhas medidas (Linux e Python 2.5) mostram que a divisão de junção e junção é quase cinco vezes mais rápida do que fazer o "re.sub (...)" e ainda três vezes mais rápida se você pré-compilar o regex uma vez e executar a operação várias vezes. E é por qualquer medida mais fácil de entender - muito mais pitônico.
Você também pode usar a técnica de divisão de string em um DataFrame do Pandas sem precisar usar .apply (..), que é útil se você precisar executar a operação rapidamente em um grande número de strings. Aqui está em uma linha:
df['message'] = (df['message'].str.split()).str.join(' ')
import re
string = re.sub('[ \t\n]+', ' ', 'The quick brown \n\n \t fox')
Isso removerá todas as guias, novas linhas e vários espaços em branco com um único espaço em branco.
Eu tentei o seguinte método e até funciona com casos extremos como:
str1=' I live on earth '
' '.join(str1.split())
Mas se você preferir uma expressão regular, isso pode ser feito como:
re.sub('\s+', ' ', str1)
Embora seja necessário fazer algum pré-processamento para remover o espaço final e final.
Em alguns casos, é desejável substituir ocorrências consecutivas de cada caractere de espaço em branco por uma única instância desse caractere. Você usaria uma expressão regular com referências anteriores para fazer isso.
(\s)\1{1,}
corresponde a qualquer caractere de espaço em branco, seguido por uma ou mais ocorrências desse caractere. Agora, tudo o que você precisa fazer é especificar o primeiro grupo ( \1
) como substituto da partida.
Agrupando isso em uma função:
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'
Uma linha de código para remover todos os espaços extras antes, depois e dentro de uma frase:
sentence = " The fox jumped over the log. "
sentence = ' '.join(filter(None,sentence.split(' ')))
Explicação:
* Os elementos restantes devem ser palavras ou palavras com pontuações, etc. Não testei isso extensivamente, mas esse deve ser um bom ponto de partida. Muito bem sucedida!
Solução para desenvolvedores de Python:
import re
text1 = 'Python Exercises Are Challenging Exercises'
print("Original string: ", text1)
print("Without extra spaces: ", re.sub(' +', ' ', text1))
Resultado:
Original string: Python Exercises Are Challenging Exercises
Without extra spaces: Python Exercises Are Challenging Exercises
O mais rápido que você pode obter para seqüências de caracteres geradas pelo usuário é:
if ' ' in text:
while ' ' in text:
text = text.replace(' ', ' ')
O curto-circuito o torna um pouco mais rápido que a resposta abrangente de pythonlarry . Faça isso se estiver buscando eficiência e procurando estritamente eliminar espaços em branco extras da variedade de espaço único .
Bastante surpreendente - ninguém postou uma função simples que será muito mais rápida do que TODAS as outras soluções postadas. Aqui vai:
def compactSpaces(s):
os = ""
for c in s:
if c != " " or os[-1] != " ":
os += c
return os
Se você estiver lidando com espaço em branco, dividir em Nenhum não incluirá uma sequência vazia no valor retornado.
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 é uma cadeia cheia de espaços e torneiras
Para remover o espaço em branco, considerando os espaços à esquerda, à direita e extra entre as palavras, use:
(?<=\s) +|^ +(?=\s)| (?= +[\n\0])
O primeiro or
lida com o espaço em branco à esquerda, o segundo or
lida com o início do espaço em branco à esquerda e o último lida com o espaço em branco à direita.
Para comprovação de uso, este link fornecerá um teste.
https://regex101.com/r/meBYli/4
Isso deve ser usado com a função re.split .
Eu tenho o meu método simples que eu usei na faculdade.
line = "I have a nice day."
end = 1000
while end != 0:
line.replace(" ", " ")
end -= 1
Isso substituirá cada espaço duplo por um único espaço e fará isso 1000 vezes. Isso significa que você pode ter 2000 espaços extras e ainda funcionará. :)
Eu tenho um método simples sem 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:
Remover todo o espaço: Você pode selecionar abaixo os acabamentos para remover o espaço em branco !! BRAliakbar Remover espaço à esquerda: Você pode selecionar os acabamentos abaixo para remover o espaço em branco !! BR Aliakbar
Remover espaços finais: Você pode selecionar os acabamentos abaixo para remover os espaços em branco !! BR Aliakbar Remover espaços à esquerda e à direita: Você pode selecionar os acabamentos abaixo para remover os espaços em branco !! BR Aliakbar Remova mais de um espaço: Você pode selecionar os acabamentos abaixo para remover o espaço em branco !! BR Aliakbar
Ainda não li muito sobre outros exemplos, mas acabei de criar esse método para consolidar vários caracteres de espaço consecutivos.
Ele não usa nenhuma biblioteca e, embora seja relativamente longo em termos de tamanho do script, não é uma implementação complexa:
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)))