Python'da virgül ve şerit boşluk ile bölün


346

Virgül üzerinde böler, ancak boşluk şerit değil bazı python kodu var:

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

Ben beyaz boşluk kaldırıldı böyle sonuçlanır:

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

Ben liste ve şerit () her öğeyi döngü farkındayım ama, bu Python olduğu için, bunu yapmanın daha hızlı, daha kolay ve daha zarif bir yolu olduğunu tahmin ediyorum.

Yanıtlar:


595

Liste kavrayışı kullanın - daha basit ve bir fordöngü kadar kolay okunabilir .

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

Bakınız: Liste Anlama ile ilgili Python belgeleri Liste anlama ile ilgili
2 saniyelik iyi bir açıklama.


1
Süper iyi! Boş liste girişlerinden kurtulmak için aşağıdaki gibi bir öğe ekledim. > text = [x.strip (), text !split ('.') içindeki x için x! = ''] ise
RandallShanePhD

@Sean: geçersiz / eksik python kodu "yazının orijinal amacı" mıydı? İnceleme wankers göre: stackoverflow.com/review/suggested-edits/21504253 . Yanlış yaparlarsa (tekrar) düzeltmeyi yaparak onlara başka türlü söyler misiniz?
Yem

Orijinal bir REPL'den kopyalandı (doğru hatırlıyorsam) ve amaç temeldeki kavramı anlamaktı (bir işlemi gerçekleştirmek için liste kavrama özelliğini kullanarak) - ama haklısın, bu liste kavrayışını görürsen daha mantıklı yeni bir liste oluşturur.
Sean Vieira

24

Normal bir ifade kullanarak bölün. Not Davayı önde gelen alanlarda daha genel yaptım. Liste kavrayışı, ön ve arka null dizeleri kaldırmaktır.

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

Bu ^\s+, eşleşmese bile çalışır :

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

İşte neden ^ \ s + 'ya ihtiyacınız var:

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

Blah'ın önde gelen alanlarını görüyor musunuz?

Açıklama: yukarıdaki Python 3 yorumlayıcısını kullanır, ancak sonuçlar Python 2'de aynıdır.


8
[x.strip() for x in my_string.split(',')]Sorulan soru için daha pitonik olduğuna inanıyorum . Belki benim çözümümün gerekli olduğu durumlar vardır. Biriyle karşılaşırsam bu içeriği güncelleyeceğim.
tbc0

Neden ^\s+gerekli? Kodunuzu onsuz test ettim ve çalışmıyor, ama nedenini bilmiyorum.
laike9m

Eğer kullanırsam re.compile("^\s*,\s*$")sonuç olur [' blah, lots , of , spaces, here '].
laike9m

@ laike9m, size farkı göstermek için cevabımı güncelledim. ^\s+yapar. Sizin de görebileceğiniz gibi, ^\s*,\s*$istenen sonuçları da döndürmez. Eğer bir regexp ile bölmek istiyorsanız, kullanın ^\s+|\s*,\s*|\s+$.
tbc0

Baştaki desen (^ \ s +) eşleşmezse ilk eşleşme boştur, böylece "foo, bar" dizesi için ['', 'foo', 'bar'] gibi bir şey alırsınız.
Steeve McCauley

21

Eklemeye geldim:

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

ama zaten Jason Orendorff tarafından söz edilmişti gördü bir açıklama .

Aynı cevaptaki Glenn Maynard'ın haritadaki liste kavrayışlarını gösteren yorumunu okurken nedenini merak etmeye başladım. Performans nedenlerinden bahsettiğini sanıyordum, ama elbette üslup nedenleriyle ya da başka bir şeyle ifade etmiş olabilir (Glenn?).

Bu yüzden bir döngüde üç yöntemi uygulayarak kutumda hızlı (muhtemelen kusurlu?) Bir test ortaya çıktı:

[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

map(str.strip, string.split(','))Kazanan yapmak , her ne kadar hepsi aynı ballparkta görünüyorlar.

Elbette harita (lambda ile veya lambda olmadan) performans nedenlerinden dolayı mutlaka göz ardı edilmemelidir ve benim için en azından bir liste kavraması kadar açıktır.

Düzenle:

Ubuntu 10.04 üzerinde Python 2.6.5


15

Bölmeden önce dizeden beyaz boşluğu çıkarmanız yeterlidir.

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

10
Virgülle ayrılmış öğeler gömülü boşluklar içeriyorsa, örneğin bir sorun "you just, broke this".
Robert Rossney

1
Geeze, bunun için -1. Siz sertsiniz. Örnek verilerinin sadece tek bir kelime olması ve verilerin kelime öbekleri olacağına dair herhangi bir spesifikasyon olmaması koşuluyla sorununu çözdü. Ama w / e, sanırım burada böyle dönüyorsun.
user489041

Yine de teşekkürler, kullanıcı. Adil olmak gerekirse ben özellikle split ve sonra şerit () istedi ve şerit lider ve sondaki boşluk kaldırır ve arasında bir şey dokunmaz. Bununla birlikte, hafif bir değişiklik ve cevabınız mükemmel bir şekilde çalışır: mylist = mystring.strip (). Split (','), ancak bunun özellikle etkili olup olmadığını bilmiyorum.
Mr_Chimp

12

Bunun zaten yanıtlandığını biliyorum, ancak bunu çok fazla bitirirseniz, düzenli ifadeler gitmek için daha iyi bir yol olabilir:

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

\sHerhangi bir boşluk karakteriyle eşleşir ve biz sadece boş bir dize ile değiştirin ''. Daha fazla bilgiyi burada bulabilirsiniz: http://docs.python.org/library/re.html#re.sub


3
Örneğiniz boşluk içeren dizelerde çalışmaz. "Örneğin, bu, biri" için "," örnek "," bir "olur. Bunun bir KÖTÜ çözüm olduğunu söylememek (benim örneğimde mükemmel çalışır) sadece eldeki göreve bağlıdır!
Mr_Chimp

Evet, bu çok doğru! Muhtemelen normal ifadeyi boşluklarla dizeleri işleyebilecek şekilde ayarlayabilirsiniz, ancak liste kavrama işe yararsa, onunla sopa diyebilirim;)
Brad Montgomery

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

bu benim için iyi çalışıyor.


2

re (normal ifadelerde olduğu gibi) aynı anda birden çok karaktere bölünmeye izin verir:

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

Bu, örnek dizeniz için iyi çalışmaz, ancak virgülle ayrılmış bir liste için iyi çalışır. Örnek dizeniz için, "bu veya bu" için bölme efekti elde etmek amacıyla regex kalıplarına bölmek için re.split gücünü birleştirebilirsiniz .

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

Ne yazık ki, bu çirkin, ama bir filterhile yapacak:

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

İşte bu kadar!


2
Neden sadece re.split(' *, *', string)?
Paul Tomblin

4
@PaulTomblin iyi fikir. Birisi de bunu yapabilirdi: re.split('[, ]*',string)aynı etki için.
Dannid

Dannid, yazdıktan sonra @ tbc0'ın cevabı gibi boşluk ve uçta boşluk bırakmadığını fark ettim.
Paul Tomblin

@PaulTomblinheh ve rebuttal'ım [, ]*listenin sonunda boş bir dize bırakıyor. Filtre hala oraya atmak için iyi bir şey, ya da üst cevapta olduğu gibi kavrayışları listelemek için iyi bir şey olduğunu düşünüyorum.
Dannid

1

map(lambda s: s.strip(), mylist)açıkça döngüden biraz daha iyi olurdu. Veya aynı anda her şey için:map(lambda s:s.strip(), string.split(','))


10
İpucu: Kendinizi her kullandığınızda map, özellikle de kullanıyorsanız lambda, bir liste kavrayışı kullanıp kullanmadığınızı görmek için iki kez kontrol edin.
Glenn Maynard

11
Lambda ile kaçınabilirsiniz map(str.strip, s.split(',')).
Jason Orendorff


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

Basitçe, virgül veya öncesinde / ardında beyaz boşluk olan / olmayan en az bir beyaz boşluk.

Deneyin lütfen!


0

map(lambda s: s.strip(), mylist)açıkça döngüden biraz daha iyi olurdu.
Veya aynı anda her şey için:

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

Temelde ihtiyacınız olan her şey budur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.