Qual é a sua aversão às listas? Eles são parte integrante da linguagem e "" .join (list_of_words) é um dos idiomas principais para transformar uma lista de strings em uma única string delimitada por espaço.
9789 PaulMcG
3
@ Tom / @ Paul: Para strings simples, a junção (string) seria simples e agradável. Mas fica mais complexo se houver outro espaço em branco que NÃO se queira perturbar ... nesse caso, as soluções "while" ou regex seriam as melhores. Postei abaixo uma junção de string que seria "correta", com resultados de teste cronometrados para três maneiras de fazer isso.
Pythonlarry
Respostas:
529
>>>import re>>> re.sub(' +',' ','The quick brown fox')'The quick brown fox'
Esta solução lida apenas com caracteres de espaço único. Não substituiria uma guia ou outros caracteres de espaço em branco manipulados por \ s, como na solução do nsr81.
21411 Taylor Leese
2
Isso é verdade, string.splittambém lida com todos os tipos de espaços em branco.
Josh Lee
6
Prefiro este porque ele se concentra apenas no caractere de espaço e não afeta caracteres como '\ n's.
Hhsaffar 17/10/2014
2
Sim certo. Mas antes dessa faixa () deve ser feita. Ele removerá espaços de ambas as extremidades.
precisa
17
Você pode usar re.sub(' {2,}', ' ', 'The quick brown fox')para impedir substituições redundantes de espaço único por espaço único .
AneesAhmed777
541
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".
Eu tenderia a alterar esse regex para r"\s\s+"que ele não tente substituir espaços já únicos.
9119 Ben Blank
19
Se você queria esse comportamento, por que não apenas "\s{2,}"uma solução alternativa para não conhecer o comportamento regex moderadamente avançado?
22720 Chris Lutz
2
lembre-se de que sub () não altera a sequência de entrada s, mas retorna o novo valor.
gcb
11
@moose - É uma otimização de legibilidade do que uma de desempenho. \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 .
Ben Blank
8
Eu desaconselho, \s\s+porque isso não normaliza um caractere TAB de volta para um espaço normal. um SPACE + TAB é substituído dessa maneira.
vdboor
51
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.
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 =' '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: A " whileversã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. Tenha em mente que o principal stmtem timeitcasos só será executada uma vez ; da maneira original que eu fiz isso, o whileloop 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 assertdeclaraçõ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:
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 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 whileloop é melhor, por uma margem decente. 32 bits 3.2, vá com o "adequado" join. 64 bits 3.3, vá para um whileloop. Novamente.
No final, pode-se melhorar o desempenho se / onde / quando necessário , mas é sempre melhor lembrar o mantra :
Eu teria preferido se você tivesse testado o simples, ' '.join(the_string.split())pois esse é o caso de uso usual, mas eu gostaria de agradecer pelo seu trabalho!
wedi
@wedi: Por outros comentários (como Gumbo ; user984003 , embora sua solução seja presuntiva e não funcione "em todos os casos"), esse tipo de solução não atende à solicitação do interlocutor. Pode-se usar .split ('') e um comp / gen, mas fica mais cabeludo para lidar com espaços de avanço / final.
Pythonlarry 26/10/14
@wedi: Por exemplo: ' '.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 '')!
Pythonlarry 26/10/14
Obrigado @pythonlarry pelo mantra! e ame o teste detalhado! Estou curioso para saber se seus pensamentos ou opiniões mudaram sobre isso desde que se passaram 6 anos?
JayRizzo 15/05/19
Versão faltante que usa geradores #
Lee Lee
42
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.
Isso remove os espaços finais. Se você quiser mantê-los fazer: texto [0: 1] + "" .join (texto [1: -1] .Split ()) + texto [-1]
user984003
4
um simples regexp é muito melhor para ler. nunca otimize o desempenho antes de precisar.
gcb
@gcb: Por que não? E se você estiver esperando um cenário de alto rendimento (por exemplo, devido à alta demanda)? Por que não implantar algo que você espera consumir menos recursos desde o início nesse cenário?
Hassan Baig
11
@HassanBaig Se você já possui o requisito de desempenho, não é realmente uma otimização prematura, certo? O que quero dizer é que, quando você ainda não precisa ficar obcecado com o desempenho, é sempre melhor buscar a legibilidade.
gcb
14
Semelhante às soluções anteriores, mas mais específico: substitua dois ou mais espaços por um:
>>>import re
>>> s ="The fox jumped over the log.">>> re.sub('\s{2,}',' ', s)'The fox jumped over the log.'
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:
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'
>>>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
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:
Divida a sequência inteira em uma lista.
Filtre os elementos vazios da lista.
Junte os elementos restantes * com um único espaç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!
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())
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 .
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 orlida com o espaço em branco à esquerda, o segundo orlida 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.
Eu tenho o meu método simples que eu usei na faculdade.
line ="I have a nice day."
end =1000while 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á. :)
Como isso difere da resposta de Anakimi (publicada mais de três anos antes)? Não é apenas uma versão mais 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:
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)))
Respostas:
fonte
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: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"
.fonte
ou
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.
fonte
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:
O one-liner essencialmente faz uma faixa de qualquer espaço à esquerda / à direita e preserva um espaço à frente / à direita (mas apenas UM ;-).
NOTA:
A "Tenha em mente que o principalwhile
versão" fez uma cópia dooriginal_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
emtimeit
casos só será executada uma vez ; da maneira original que eu fiz isso, owhile
loop funcionou no mesmo rótulooriginal_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. Adicioneiassert
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: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 umwhile
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!
fonte
' '.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 mesmoparts = 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,
é 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.
fonte
Semelhante às soluções anteriores, mas mais específico: substitua dois ou mais espaços por um:
fonte
Uma alma simples
fonte
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:
fonte
Isso removerá todas as guias, novas linhas e vários espaços em branco com um único espaço em branco.
fonte
Eu tentei o seguinte método e até funciona com casos extremos como:
Mas se você preferir uma expressão regular, isso pode ser feito como:
Embora seja necessário fazer algum pré-processamento para remover o espaço final e final.
fonte
Isso também parece funcionar:
Onde a variável
s
representa sua sequência.fonte
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:
fonte
Outra alternativa:
fonte
Uma linha de código para remover todos os espaços extras antes, depois e dentro de uma frase:
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!
fonte
Solução para desenvolvedores de Python:
Resultado:
Original string: Python Exercises Are Challenging Exercises Without extra spaces: Python Exercises Are Challenging Exercises
fonte
fonte
O mais rápido que você pode obter para seqüências de caracteres geradas pelo usuário é:
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 .
fonte
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:
fonte
Se você estiver lidando com espaço em branco, dividir em Nenhum não incluirá uma sequência vazia no valor retornado.
5.6.1 Métodos de string, str.split ()
fonte
Resultados :
fonte
Para remover o espaço em branco, considerando os espaços à esquerda, à direita e extra entre as palavras, use:
O primeiro
or
lida com o espaço em branco à esquerda, o segundoor
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 .
fonte
Eu tenho o meu método simples que eu usei na faculdade.
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á. :)
fonte
Eu tenho um método simples sem dividir:
fonte
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
fonte
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:
fonte