Dividi per virgola e rimuovi spazi bianchi in Python


346

Ho un po 'di codice Python che si divide su virgola, ma non spoglia lo spazio bianco:

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

Preferirei finire con gli spazi rimossi in questo modo:

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

Sono consapevole che potrei scorrere l'elenco e rimuovere () ogni elemento ma, dato che si tratta di Python, immagino che ci sia un modo più rapido, semplice ed elegante per farlo.

Risposte:


594

Usa la comprensione dell'elenco: più semplice e facile da leggere come un forciclo.

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

Vedi: Documenti Python sulla comprensione delle liste
Una buona spiegazione di 2 secondi sulla comprensione delle liste.


1
Molto bene! Ho aggiunto un elemento come segue per eliminare le voci dell'elenco vuoto. > text = [x.strip () per x in text.split ('.') if x! = '']
RandallShanePhD

@Sean: il codice pitone non valido / incompleto era il tuo "intento originale del post"? Secondo i segaieri della recensione era: stackoverflow.com/review/suggested-edits/21504253 . Potete per favore dirgli diversamente facendo la correzione se sono (di nuovo) sbagliati?
Foraggio il

L'originale è stato copiato e incollato da un REPL (se ricordo bene) e l'obiettivo era la comprensione del concetto sottostante (usare la comprensione dell'elenco per eseguire un'operazione) - ma hai ragione, ha più senso se vedi quella comprensione dell'elenco produce un nuovo elenco.
Sean Vieira,

24

Dividi usando un'espressione regolare. Nota ho reso il caso più generale con spazi iniziali. La comprensione dell'elenco consiste nel rimuovere le stringhe null nella parte anteriore e posteriore.

>>> 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']

Funziona anche se ^\s+non corrisponde:

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

Ecco perché hai bisogno di ^ \ s +:

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

Vedi gli spazi principali in blah?

Chiarimento: sopra usa l'interprete Python 3, ma i risultati sono gli stessi in Python 2.


8
Credo che [x.strip() for x in my_string.split(',')]sia più pitonico per la domanda posta. Forse ci sono casi in cui la mia soluzione è necessaria. Aggiornerò questo contenuto se ne incontrassi uno.
martedì

Perché è ^\s+necessario Ho testato il tuo codice senza di esso e non funziona, ma non so perché.
laike9m

Se uso re.compile("^\s*,\s*$"), il risultato è [' blah, lots , of , spaces, here '].
laike9m

@ laike9m, ho aggiornato la mia risposta per mostrarti la differenza. ^\s+fa. Come puoi vedere da solo, ^\s*,\s*$non restituisce neanche i risultati desiderati. Quindi, se vuoi dividere con una regexp, usa ^\s+|\s*,\s*|\s+$.
martedì

La prima corrispondenza è vuota se il modello principale (^ \ s +) non corrisponde quindi ottieni qualcosa come ['', 'pippo', 'bar'] per la stringa "pippo, barra".
Steeve McCauley,

21

Sono venuto per aggiungere:

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

ma ho visto che era già stato menzionato da Jason Orendorff in un commento .

Leggendo il commento di Glenn Maynard nella stessa risposta che suggerisce la comprensione dell'elenco sulla mappa, ho iniziato a chiedermi perché. Ho pensato che intendesse per motivi di performance, ma ovviamente avrebbe potuto significare per motivi stilistici o qualcos'altro (Glenn?).

Quindi un rapido test (forse imperfetto?) Sulla mia scatola che applica i tre metodi in un ciclo ha rivelato:

[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

rendendo map(str.strip, string.split(','))il vincitore, anche se sembra che siano tutti nello stesso campo.

Certamente però la mappa (con o senza una lambda) non dovrebbe necessariamente essere esclusa per motivi di performance, e per me è almeno chiara come la comprensione di un elenco.

Modificare:

Python 2.6.5 su Ubuntu 10.04


15

Basta rimuovere lo spazio bianco dalla stringa prima di dividerlo.

mylist = my_string.replace(' ','').split(',')

10
Tipo di problema se gli elementi separati da virgole contengono spazi incorporati, ad es "you just, broke this".
Robert Rossney,

1
Accidenti, un -1 per questo. Ragazzi siete duri. Risolveva il suo problema, fornendo i suoi dati di esempio erano solo parole singole e non c'era specifica che i dati sarebbero stati frasi. Ma immagino sia il modo in cui voi ragazzi giriate qui.
user489041

Bene grazie comunque, utente. Ad essere sinceri, ho chiesto espressamente di dividere e quindi strip () e strip rimuove gli spazi bianchi iniziali e finali e non tocca nulla in mezzo. Una leggera modifica e la tua risposta funzionerebbero perfettamente, però: mylist = mystring.strip (). Split (',') anche se non so se questo sia particolarmente efficiente.
Mr_Chimp,

12

So che è già stata data una risposta, ma se finisci di farlo molto, le espressioni regolari potrebbero essere un modo migliore di procedere:

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

L' \scorrisponde a qualsiasi carattere di spazio, e abbiamo appena sostituirla con una stringa vuota ''. Puoi trovare maggiori informazioni qui: http://docs.python.org/library/re.html#re.sub


3
Il tuo esempio non funzionerebbe su stringhe contenenti spazi. "per esempio, uno" diventerebbe "per", "esempio", "uno". Non dire che è una BAD soluzione (funziona perfettamente sul mio esempio) dipende solo dal compito in mano!
Mr_Chimp,

Sì, è molto corretto! Probabilmente potresti regolare la regexp in modo che possa gestire stringhe con spazi, ma se la comprensione dell'elenco funziona, direi di attenersi ad essa;)
Brad Montgomery

2
import re
result=[x for x in re.split(',| ',your_string) if x!='']

questo funziona bene per me.


2

re (come nelle espressioni regolari) consente la suddivisione su più caratteri contemporaneamente:

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

Questo non funziona bene per la stringa di esempio, ma funziona bene per un elenco separato da virgole. Per la tua stringa di esempio, puoi combinare la potenza re.split per dividere i pattern regex per ottenere un effetto "split-on-this-or-that".

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

Sfortunatamente, è brutto, ma la filtervolontà farà il trucco:

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

Ecco!


2
Perché non solo re.split(' *, *', string)?
Paul Tomblin,

4
@PaulTomblin buona idea. Si può anche aver fatto questo: re.split('[, ]*',string)per lo stesso effetto.
Dannid,

Dannid mi sono reso conto dopo aver scritto che non toglie spazio all'inizio e alla fine come fa la risposta di @ tbc0.
Paul Tomblin,

@PaulTomblinheh, e la mia confutazione [, ]*lascia una stringa vuota alla fine dell'elenco. Penso che il filtro sia ancora una cosa carina da inserire o attenersi alla comprensione dell'elenco come fa la risposta migliore.
Dannid,

1

map(lambda s: s.strip(), mylist)sarebbe un po 'meglio del loop esplicito. O per tutto in una volta:map(lambda s:s.strip(), string.split(','))


10
Suggerimento: ogni volta che ti ritrovi a utilizzare map, in particolare se lo stai utilizzando lambda, ricontrolla per vedere se dovresti utilizzare una comprensione dell'elenco.
Glenn Maynard,

11
Puoi evitare la lambda con map(str.strip, s.split(',')).
Jason Orendorff,


1
import re
mylist = [x for x in re.compile('\s*[,|\s+]\s*').split(string)]

Semplicemente, virgola o almeno uno spazi bianchi con / senza spazi bianchi precedenti / successivi.

Vi preghiamo di provare!


0

map(lambda s: s.strip(), mylist)sarebbe un po 'meglio del loop esplicito.
O per tutto in una volta:

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

È praticamente tutto ciò di cui hai bisogno.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.