Dividido por vírgula e espaço em branco da tira em Python

346

Eu tenho algum código python que se divide em vírgula, mas não tira o espaço em branco:

>>> string = "blah, lots  ,  of ,  spaces, here "
>>> mylist = string.split(',')
>>> print mylist
['blah', ' lots  ', '  of ', '  spaces', ' here ']

Prefiro acabar com o espaço em branco removido assim:

['blah', 'lots', 'of', 'spaces', 'here']

Estou ciente de que poderia percorrer a lista e extrair () cada item, mas, como esse é Python, acho que há uma maneira mais rápida, fácil e elegante de fazê-lo.

Mr_Chimp
fonte

Respostas:

594

Use a compreensão da lista - mais simples e fácil de ler como um forloop.

my_string = "blah, lots  ,  of ,  spaces, here "
result = [x.strip() for x in my_string.split(',')]
# result is ["blah", "lots", "of", "spaces", "here"]

Veja: Documentos em Python sobre compreensão de lista
Uma boa explicação de 2 segundos sobre compreensão de lista.

Sean Vieira
fonte
11
Super bom! Adicionei um item da seguinte maneira para se livrar das entradas da lista em branco. > text = [x.strip () para x em text.split ('.') se x! = ''] #
487 RandallShanePhD
@ Sean: o código python inválido / incompleto era sua "intenção original da publicação"? De acordo com os wankers de revisão, era: stackoverflow.com/review/suggested-edits/21504253 . Você pode dizer o contrário, fazendo a correção se estiver errado (de novo)?
Forragem
O original foi copiado e colado de um REPL (se bem me lembro) e o objetivo era entender o conceito subjacente (usando a compreensão da lista para executar uma operação) - mas você está certo, faz mais sentido se você entender essa lista produz uma nova lista.
Sean Vieira
24

Divida usando uma expressão regular. Note que tornei o caso mais geral com espaços à esquerda. A compreensão da lista é remover as cadeias nulas na frente e atrás.

>>> import re
>>> string = "  blah, lots  ,  of ,  spaces, here "
>>> pattern = re.compile("^\s+|\s*,\s*|\s+$")
>>> print([x for x in pattern.split(string) if x])
['blah', 'lots', 'of', 'spaces', 'here']

Isso funciona mesmo ^\s+que não corresponda:

>>> string = "foo,   bar  "
>>> print([x for x in pattern.split(string) if x])
['foo', 'bar']
>>>

Veja por que você precisa de ^ \ s +:

>>> pattern = re.compile("\s*,\s*|\s+$")
>>> print([x for x in pattern.split(string) if x])
['  blah', 'lots', 'of', 'spaces', 'here']

Veja os espaços principais em blá?

Esclarecimento: acima usa o interpretador Python 3, mas os resultados são os mesmos no Python 2.

tbc0
fonte
8
Eu acredito que [x.strip() for x in my_string.split(',')]é mais pitônico para a pergunta. Talvez haja casos em que minha solução é necessária. Atualizarei esse conteúdo se eu encontrar um.
tbc0
Por que é ^\s+necessário? Testei seu código sem ele e ele não funciona, mas não sei por quê.
precisa saber é o seguinte
Se eu usar re.compile("^\s*,\s*$"), o resultado é [' blah, lots , of , spaces, here '].
precisa saber é o seguinte
@ laike9m, atualizei minha resposta para mostrar a diferença. ^\s+faz. Como você pode ver por si mesmo, ^\s*,\s*$também não retorna os resultados desejados. Portanto, se você deseja dividir com uma regexp, use ^\s+|\s*,\s*|\s+$.
usar o seguinte comando
A primeira correspondência estará vazia se o padrão inicial (^ \ s +) não corresponder, então você obtém algo como ['', 'foo', 'bar'] para a string "foo, bar".
Steeve McCauley
21

Eu vim para adicionar:

map(str.strip, string.split(','))

mas vi que já havia sido mencionado por Jason Orendorff em um comentário .

Lendo o comentário de Glenn Maynard na mesma resposta, sugerindo a compreensão da lista no mapa, comecei a me perguntar por quê. Eu assumi que ele quis dizer por razões de desempenho, mas é claro que ele poderia ter falado por razões estilísticas ou algo mais (Glenn?).

Então, um teste rápido (possivelmente defeituoso?) Na minha caixa, aplicando os três métodos em um loop, revelou:

[word.strip() for word in string.split(',')]
$ time ./list_comprehension.py 
real    0m22.876s

map(lambda s: s.strip(), string.split(','))
$ time ./map_with_lambda.py 
real    0m25.736s

map(str.strip, string.split(','))
$ time ./map_with_str.strip.py 
real    0m19.428s

tornando map(str.strip, string.split(','))o vencedor, embora pareça que eles estão todos no mesmo estádio.

Certamente, embora o mapa (com ou sem um lambda) não deva ser necessariamente descartado por razões de desempenho, e para mim é pelo menos tão claro quanto a compreensão de uma lista.

Editar:

Python 2.6.5 no Ubuntu 10.04

Sean
fonte
15

Apenas remova o espaço em branco da string antes de dividi-la.

mylist = my_string.replace(' ','').split(',')
user489041
fonte
10
Tipo de problema se os itens separados por vírgulas contiverem espaços incorporados, por exemplo "you just, broke this".
Robert Rossney
11
Nossa, um -1 para isso. Vocês são durões. Ele resolveu o problema, fornecendo dados de amostra apenas com palavras únicas e não havia especificação de que os dados seriam frases. Mas acho que é assim que vocês rolam por aqui.
user489041
Bem, obrigado de qualquer maneira, usuário. Para ser justo, pedi especificamente divisão e, em seguida, strip () e strip remove os espaços em branco iniciais e finais e não toca em nada no meio. Uma pequena alteração e sua resposta funcionaria perfeitamente, no entanto: mylist = mystring.strip (). Split (',') embora eu não saiba se isso é particularmente eficiente.
Mr_Chimp
12

Sei que isso já foi respondido, mas se você terminar muito isso, expressões regulares podem ser o melhor caminho a seguir:

>>> import re
>>> re.sub(r'\s', '', string).split(',')
['blah', 'lots', 'of', 'spaces', 'here']

Ele \scorresponde a qualquer caractere de espaço em branco e apenas o substituímos por uma string vazia ''. Você pode encontrar mais informações aqui: http://docs.python.org/library/re.html#re.sub

Brad Montgomery
fonte
3
Seu exemplo não funcionaria em cadeias contendo espaços. "por exemplo, um" se tornaria "para", "examina este", "um". Não estou dizendo que é uma solução MAU (funciona perfeitamente no meu exemplo), só depende da tarefa em mãos!
Mr_Chimp
Sim, isso é muito correto! Você provavelmente poderia ajustar a regexp para que ele possa lidar com cordas com espaços, mas se a compreensão da lista funciona, eu diria que ficar com ela;)
Brad Montgomery
2
import re
result=[x for x in re.split(',| ',your_string) if x!='']

Este trabalho é bom para mim.

Zieng
fonte
2

re (como em expressões regulares) permite dividir vários caracteres ao mesmo tempo:

$ string = "blah, lots  ,  of ,  spaces, here "
$ re.split(', ',string)
['blah', 'lots  ', ' of ', ' spaces', 'here ']

Isso não funciona bem para sua sequência de exemplo, mas funciona bem para uma lista separada por vírgula-espaço. Para o seu exemplo de seqüência, você pode combinar o poder re.split para dividir nos padrões regex para obter um efeito "dividir isso ou aquilo".

$ re.split('[, ]',string)
['blah',
 '',
 'lots',
 '',
 '',
 '',
 '',
 'of',
 '',
 '',
 '',
 'spaces',
 '',
 'here',
 '']

Infelizmente, isso é feio, mas a filterfará o truque:

$ filter(None, re.split('[, ]',string))
['blah', 'lots', 'of', 'spaces', 'here']

Voila!

Dannid
fonte
2
Por que não apenas re.split(' *, *', string)?
Paul Tomblin
4
@PaulTomblin good idea. Também se pode ter feito isso: re.split('[, ]*',string)para o mesmo efeito.
Dannid
Dannid, depois de escrever, percebi que ele não tira os espaços em branco no começo e no fim, como a resposta de @ tbc0.
Paul Tomblin
@PaulTomblinheh, e minha refutação [, ]*deixa uma string vazia no final da lista. Eu acho que o filtro ainda é uma boa coisa para colocar lá, ou manter a compreensão da lista como a resposta principal faz.
1111 Dannid
1

map(lambda s: s.strip(), mylist)seria um pouco melhor do que fazer um loop explicitamente. Ou para a coisa toda de uma vez:map(lambda s:s.strip(), string.split(','))

user470379
fonte
10
Dica: sempre que mapvocê estiver usando , principalmente se estiver usando lambda, verifique novamente se você deve usar uma compreensão de lista.
perfil completo de Glenn Maynard
11
Você pode evitar o lambda com map(str.strip, s.split(',')).
Jason Orendorff
1
s = 'bla, buu, jii'

sp = []
sp = s.split(',')
for st in sp:
    print st
Parikshit Pandya
fonte
1
import re
mylist = [x for x in re.compile('\s*[,|\s+]\s*').split(string)]

Simplesmente, vírgula ou pelo menos um espaço em branco com / sem espaços em branco anteriores / sucessivos.

Tente por favor!

GyuHyeon Choi
fonte
0

map(lambda s: s.strip(), mylist)seria um pouco melhor do que fazer um loop explicitamente.
Ou para a coisa toda de uma vez:

map(lambda s:s.strip(), string.split(','))

Isso é basicamente tudo o que você precisa.

DJbigpenis
fonte