Bölünmüş () sonuçlarında boş dizeler neden döndürülür?


120

Geri '/segment/segment/'.split('/')dönmenin anlamı nedir ['', 'segment', 'segment', '']?

Boş öğelere dikkat edin. Bir dizenin birinci konumunda ve en sonunda olan bir sınırlayıcıyı bölüyorsanız, her uçtan boş dizenin döndürülmesi size hangi ekstra değeri verir?


1
Aynı soruyu soruyorum ve uzun süre aradım. Artık boş sonuçların gerçekten önemli olduğunu anlıyorum. Sorunuz için teşekkürler.
emeraldhieu

2
Bir çözüm, strip()'/segment/segment/'.strip('/').split('/')
ayırmadan

Yanıtlar:


178

str.splittamamlar str.join, yani

"/".join(['', 'segment', 'segment', ''])

orijinal dizeyi geri alır.

Boş dizeler orada '/'olmasaydı , ilk ve sonuncu dizeden sonra eksik olurdu.join()


11
Basit, ancak soruyu tam olarak yanıtlıyor.
orokusaki

Kıvırcık alıntıların Python'da gerçekten geçerli olduğunu keşfettiğimde şok oldum ... ama, ama ... nasıl? Doktorlar bundan bahsetmiyor gibi görünüyor.
Tim Pietzcker

@Tim, bu alıntıların oraya nasıl girdiği hakkında hiçbir fikrim yok: /
John La Rooy

7
Öyleyse, Python IDE'niz olarak Microsoft Word'ü kullanmıyorsunuz? :)
Tim Pietzcker

1
@ aaa90210 kim basit cevapların en iyisi olmadığını söyledi? Cevabın nasıl basit olduğuna dair bir yorumdu (ilk olarak 5 yıl önce), ancak soruyu tam olarak cevapladı. Bir cümlede "ama" kullanmak kötü bir şey ifade etmez. Basit olmayan bir cevap, daha eksiksiz bir cevap olabilir (örneğin, ilgili kararlar veya belirtilen işlevsellikle ilgili bir PEP dahil).
orokusaki

89

Daha genel olarak, split()sonuçlarda döndürülen boş dizeleri kaldırmak için filterişleve bakmak isteyebilirsiniz .

Misal:

filter(None, '/segment/segment/'.split('/'))

İadeler

['segment', 'segment']

3
Bunun için teşekkür ederim, bu cevabın neden bu kadar aşağı olduğunu bilmiyorum, geri kalan her şey ilkel şeyler.
takoz

6
Çıktı olarak bir filtre nesnesi almak yerine sonucun bir listede toplanması isteniyorsa, tüm filtre yapısını içine koyun list(...).
Tim Visée

29

Burada dikkate alınması gereken iki ana nokta vardır:

  • Sonucunun '/segment/segment/'.split('/')eşit olmasını beklemek ['segment', 'segment']mantıklıdır, ancak o zaman bu bilgiyi kaybeder. İstediğin gibi split()çalıştıysa a.split('/') == ['segment', 'segment'], sana bunu söylersem, bana ne aolduğunu söyleyemezsin .
  • Be'nin sonucu ne olmalı 'a//b'.split()? ['a', 'b']? veya ['a', '', 'b']? Yani, split()bitişik sınırlayıcıları birleştirmeli mi? Gerekirse, bir karakterle ayrılmış verileri ayrıştırmak çok zor olacaktır ve bazı alanlar boş olabilir. Eminim pek çok insan var oldukça ben do yukarıdaki durum için sonuç boş değerler istiyorum!

Sonunda, iki şeye indirgeniyor:

Tutarlılık: nsınırlayıcılarım varsa içinde a, n+1değerleri split().

Karmaşık şeyler yapmak mümkün olmalı ve basit şeyler yapmak kolay olmalıdır: eğer boş dizeleri göz ardı etmek split()istiyorsanız, her zaman şunları yapabilirsiniz:

def mysplit(s, delim=None):
    return [x for x in s.split(delim) if x]

biri boş değerler göz ardı etmek istemiyor ama eğer biri olmalı yapabilmelidir.

Dilin bir tanımını seçmesi gerekir split() — varsayılan olarak herkesin gereksinimlerini karşılamak için çok fazla farklı kullanım durumu vardır. Python'un seçiminin iyi ve en mantıklı olduğunu düşünüyorum. (Bir kenara, C'leri sevmememin nedenlerinden biristrtok() C'leri sevmeme bitişik sınırlayıcıları birleştirerek ciddi ayrıştırma / jetonlaştırma yapmayı son derece zorlaştırmasıdır.)

Bir istisna vardır: a.split()bir argüman olmadan ardışık beyaz boşluğu sıkıştırır, ancak bu durumda yapılacak doğru şeyin bu olduğu iddia edilebilir. Davranışı istemiyorsan, her zaman yapabilirsin a.split(' ').


Yinelenen boşlukları bombalamanın, sonra bölmenin veya ayırmanın ve yalnızca boş olmayan dizeleri almanın daha hızlı olup olmadığını merak edenler için şunu elde ederim: python3 -m timeit "import re ; re.sub(' +', ' foo bar baz ', '').split(' ')"-> döngü başına 875 ns; python3 -m timeit "[token for token in ' foo bar baz '.split(' ') if token]"-> döngü başına 616
nsn

8

Having x.split(y)listesini döndürür hep 1 + x.count(y)öğeleri değerli düzen - bu yapar dışarı @ gnibbler zaten doğrultuyor olarak splitve joinbirbirlerinin tam inversleri (Açıkçası olması gerektiği gibi), o da kesin olarak ayraç-katılan kayıtların her türlü semantik (haritalar gibi csvdosya hatları [[sorunları Tırnaklamanın net]], gelen çizgiler /etc/groupdosya yolları ve URL'ler) içinde (göreli yollar vs mutlak Unix içinde, vb), bu Roman'ın cevabı söz @ gibi (sağlar) (örn kolay çekler), ve benzeri.

Buna bakmanın bir başka yolu da, herhangi bir kazanç elde etmek için bilgileri istemeden pencereden dışarı atmamalısınız. x.split(y)Eşdeğeri yapılırsa ne elde edilir x.strip(y).split(y)? Hiçbir şey, tabii ki - ilk form keyfi ikincisini anlamında görüldü eğer zaman o en ne demek, ama yapmanız sürü iş olurdu zaman ikinci bir form kullanımı kolay ilkini istiyorum ( Bu, önceki paragrafta da belirtildiği gibi, ender olmaktan uzaktır).

Ama gerçekten, matematiksel düzenlilik açısından düşünmek, kendinize başarılı API'ler tasarlamayı öğretmenin en basit ve en genel yoludur. Farklı bir örnek vermek gerekirse, herhangi bir geçerli xve y x == x[:y] + x[y:]- dilimlemenin neden bir aşırılığının hariç tutulması gerektiğini hemen gösterir . Formüle edebileceğiniz değişmez iddia ne kadar basitse, sonuçta ortaya çıkan anlambilimin gerçek hayatta ihtiyaç duyduğunuz şey olma olasılığı o kadar yüksektir - matematiğin evrenle başa çıkmada çok yararlı olduğu mistik gerçeğinin bir parçası.

splitBaştaki ve sondaki sınırlayıcıların özel harfli olduğu bir diyalekt için değişmezi formüle etmeyi deneyin ... karşı örnek: isspaceen fazla basit olmayanlar gibi dize yöntemleri - x.isspace()eşdeğerdir x and all(c in string.whitespace for c in x)- bu aptalca liderlik x and, kendinizi sık sık kodlama bulmanızın nedenidir not x or x.isspace(), olması gereken basitliğe geri dönmek içinis... dizi yöntemlerinde tasarlanmış gereken (burada boş bir dizge "istediğiniz herhangi bir şeydir" - sokaktaki adam at anlamının aksine, belki [[boş kümeler, sıfır gibi & c, her zaman çoğu insanın kafasını karıştırmıştır ;-)]], ancak aşikar, iyi rafine edilmiş matematiksel sağduyuya tamamen uymaktadır ! -).


5

Ne tür bir cevap aradığınızdan emin değilim? Üç eşleşme elde edersiniz çünkü üç sınırlayıcınız vardır. Boş olanı istemiyorsanız, şunu kullanın:

'/segment/segment/'.strip('/').split('/')

4
-1 çünkü üç değil dört eşleşme elde edersiniz ve bu da soruyu gerçekten cevaplamaz.
Roma

1
Negatife karşı koymak için +1 .. Üç sonucu geri alacağını söylemedi. Bana mantıklı gelen "üç sınırlayıcı" için "üç eşleşme" dedi. Bununla birlikte, hiçbir şeyden "dört eşleşme" elde edemezsiniz. Yine de sonucunuzda "dört öğe" döndürülür. Ayrıca, doğrudan "neden" sorusuna yanıt vermiyor, ancak gerçekten istediğini elde etmenin basit bir yolunu sağlıyor ... ki bunun olumsuz bir oyu hak ettiğini düşünmüyorum. Birini eleştirecekseniz (olumsuz oyla, daha az değil) lütfen daha dikkatli olun! Şerefe! 8 ^)
kodybrown

@wasatchwizard Açıklama için teşekkürler. Düzeltmeyi ve tavsiyeyi takdir ediyorum. Maalesef şimdi oyum kilitlendi ve değiştirilemez.
Roma

Çözümünüzü seviyorum - soyun ve boş sonucu gidermek için ayırın
Nam G VU

5

Orada bir sınırlayıcı olduğunu bilmenizi sağlar. Dolayısıyla, 4 sonuç görmek 3 sınırlayıcınız olduğunu bilmenizi sağlar. Bu, Python'un boş öğeleri bırakmasını sağlamak yerine, bu bilgilerle istediğinizi yapma gücü verir ve ardından bilmeniz gerekiyorsa sınırlayıcıları başlatmayı veya bitirmeyi manuel olarak kontrol etmenizi sağlar.

Basit örnek: Mutlak ve göreceli dosya adlarını kontrol etmek istediğinizi varsayalım. Bu şekilde, dosya adınızın ilk karakterinin ne olduğunu kontrol etmek zorunda kalmadan hepsini bölme ile yapabilirsiniz.


1

Bu minimal örneği düşünün:

>>> '/'.split('/')
['', '']

splitsınırlayıcıdan önce ve sonra ne olduğunu size vermelidir '/', ancak başka karakter yoktur. O yüzden vardır size teknik olarak önce gelen ve şu boş dize, vermek '/', çünkü '' + '/' + '' == '/'.

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.