Python 'string' alt dizesi yöntemine sahip mi?


3599

Python'da bir string.containsveya string.indexofyöntem arıyorum .

Ben yapmak istiyorum:

if not somestring.contains("blah"):
   continue

Yanıtlar:


6261

inOperatörü kullanabilirsiniz :

if "blah" not in somestring: 
    continue

231
Kaputun altında, Python kullanacağız __contains__(self, item), __iter__(self)ve __getitem__(self, key)belirli bir bir öğe yatıyor içerip içermediğini belirlemek için bu sırayla. inÖzel türünüze sunmak için bu yöntemlerden en az birini uygulayın .
BallpointBen

27
Sadece bir şeylerin Yok olmayacağından emin olun. Aksi takdirde birTypeError: argument of type 'NoneType' is not iterable
Büyük Balkabağı

5
FWIW, bu hedefe ulaşmanın deyimsel yoludur.
Trenton

6
Dizeler için Python inoperatörü Rabin-Carp algoritmasını kullanıyor mu?
Sam Chats

3
@SamChats uygulama ayrıntıları için stackoverflow.com/questions/18139660/… adresine bakın (CPython; afaik'te dil spesifikasyonu burada herhangi bir algoritmayı zorunlu kılmaz).
Christoph Burschka

667

Bu yalnızca bir alt dize aramasıysa kullanabilirsiniz string.find("substring").

Sen biraz dikkatli olmak gerekiyor find, indexve inonlar aramalar alt dize gibi olsa. Başka bir deyişle, bu:

s = "This be a string"
if s.find("is") == -1:
    print("No 'is' here!")
else:
    print("Found 'is' in the string.")

Bu yazdıracak Found 'is' in the string., Benzer if "is" in s:etmek değerlendirirsiniz True. İstediğiniz şey bu olabilir veya olmayabilir.


78
Alt dize aramalarında yer alan gotcha'ları vurgulamak için +1. bariz çözüm (muhtemelen) beklendiği gibi if ' is ' in s:geri dönecektir False.
aaronasterling

95
@aaronasterling Açıkçası olabilir, ama tamamen doğru olmayabilir. Noktalama işaretleriniz varsa veya başlangıçta veya sonundaysa ne olur? Büyük harf kullanımına ne dersiniz? Daha iyi bir durum duyarsız regex araması \bis\b(kelime sınırları) olurdu .
Bob

2
@JamieBull Bir kez daha, noktalama işaretini bir sözcük için ayırıcı olarak eklemek isteyip istemediğinizi düşünmelisiniz. Bölünme, naif bir kontrol çözümü ile büyük ölçüde aynı etkiye sahip olacaktır ' is ', özellikle yakalanmayacaktır This is, a comma'veya 'It is.'.
Bob

7
@JamieBull: Herhangi bir gerçek giriş bölünmüş bir s.split(string.punctuation + string.whitespace)kez bile bölünecek şüpheliyim ; / / fonksiyon ailesi splitgibi değil , sadece tüm sınırlayıcı karakterleri bitişik olarak bu sırayla gördüğünde böler. Karakter sınıflarına bölmek istiyorsanız, düzenli ifadelere geri dönersiniz (hangi noktada, bölmeden arama yapmak daha basit ve daha hızlı bir yoldur). striprstriplstripr'\bis\b'
ShadowRanger

8
'is' not in (w.lower() for w in s.translate(string.maketrans(' ' * len(string.punctuation + string.whitespace), string.punctuation + string.whitespace)).split()- tamam, puan alındı. Bu çok saçma ...
Jamie Bull

190

Python'un alt dize yöntemi içeren bir dizesi var mı?

Evet, ancak Python'un bunun yerine kullanmanız gereken bir karşılaştırma operatörü vardır, çünkü dil kullanımını amaçlamaktadır ve diğer programcılar bunu kullanmanızı bekler. inBir karşılaştırma operatörü olarak kullanılan bu anahtar kelime :

>>> 'foo' in '**foo**'
True

Orijinal sorunun sorduğu tam tersi (tamamlayıcı) not in:

>>> 'foo' not in '**foo**' # returns False
False

Bu semantik olarak aynıdır, not 'foo' in '**foo**'ancak daha okunabilir ve açıkça okunabilirlik iyileştirmesi olarak dilde sağlanmıştır.

Kullanmaktan kaçının __contains__, findveindex

Söz verildiği gibi, burada containsyöntem:

str.__contains__('**foo**', 'foo')

döner True. Bu işlevi süper sicim örneğinden de çağırabilirsiniz:

'**foo**'.__contains__('foo')

Ama yapma. Alt çizgilerle başlayan yöntemler semantik olarak özel kabul edilir. Bunu kullanmanın tek nedeni inve not inişlevlerini genişletirken (örn. Alt sınıflama str):

class NoisyString(str):
    def __contains__(self, other):
        print('testing if "{0}" in "{1}"'.format(other, self))
        return super(NoisyString, self).__contains__(other)

ns = NoisyString('a string with a substring inside')

ve şimdi:

>>> 'substring' in ns
testing if "substring" in "a string with a substring inside"
True

Ayrıca, aşağıdaki dize yöntemlerinden kaçının:

>>> '**foo**'.index('foo')
2
>>> '**foo**'.find('foo')
2

>>> '**oo**'.find('foo')
-1
>>> '**oo**'.index('foo')

Traceback (most recent call last):
  File "<pyshell#40>", line 1, in <module>
    '**oo**'.index('foo')
ValueError: substring not found

Diğer dillerin doğrudan alt dizeleri test etmek için bir yöntemi olmayabilir ve bu nedenle bu tür yöntemleri kullanmanız gerekir, ancak Python ile inkarşılaştırma işlecini kullanmak çok daha etkilidir .

Performans karşılaştırmaları

Aynı hedefe ulaşmanın çeşitli yollarını karşılaştırabiliriz.

import timeit

def in_(s, other):
    return other in s

def contains(s, other):
    return s.__contains__(other)

def find(s, other):
    return s.find(other) != -1

def index(s, other):
    try:
        s.index(other)
    except ValueError:
        return False
    else:
        return True



perf_dict = {
'in:True': min(timeit.repeat(lambda: in_('superstring', 'str'))),
'in:False': min(timeit.repeat(lambda: in_('superstring', 'not'))),
'__contains__:True': min(timeit.repeat(lambda: contains('superstring', 'str'))),
'__contains__:False': min(timeit.repeat(lambda: contains('superstring', 'not'))),
'find:True': min(timeit.repeat(lambda: find('superstring', 'str'))),
'find:False': min(timeit.repeat(lambda: find('superstring', 'not'))),
'index:True': min(timeit.repeat(lambda: index('superstring', 'str'))),
'index:False': min(timeit.repeat(lambda: index('superstring', 'not'))),
}

Ve şimdi kullanmanın indiğerlerinden çok daha hızlı olduğunu görüyoruz . Eşdeğer bir işlem yapmak için daha az zaman daha iyidir:

>>> perf_dict
{'in:True': 0.16450627865128808,
 'in:False': 0.1609668098178645,
 '__contains__:True': 0.24355481654697542,
 '__contains__:False': 0.24382793854783813,
 'find:True': 0.3067379407923454,
 'find:False': 0.29860888058124146,
 'index:True': 0.29647137792585454,
 'index:False': 0.5502287584545229}

6
Neden kaçınmalı str.indexve str.find? Başka birinin bir alt dizenin dizinini yalnızca var olup olmamasından ziyade bulmasını nasıl önerirsiniz? (veya bunları içerdikleri yerde kullanmaktan kaçınmayı mı kastediyordunuz - bu yüzden s.find(ss) != -1bunun yerine kullanmayın ss in s?)
coderforlife

3
Kesinlikle öyle olsa da, bu yöntemlerin kullanımının arkasındaki amaç remodülün zarif kullanımı ile daha iyi ele alınabilir . Henüz yazdığım herhangi bir kodda str.index veya str.find için bir kullanım bulamadım.
Aaron Hall

Lütfen kullanmaya karşı tavsiyeye verdiğiniz cevabı da uzatınız str.count( string.count(something) != 0). titreme
cs95

operatorModül sürümü nasıl çalışır ?
jpmc26

@ jpmc26 in_yukarıdakiyle aynıdır - ancak etrafında bir yığın çerçevesiyle, bundan daha yavaştır: github.com/python/cpython/blob/3.7/Lib/operator.py#L153
Aaron Hall

175

if needle in haystack:@Michael'in dediği gibi normal kullanımdır - inoperatöre, bir yöntem çağrısından daha okunabilir ve daha hızlı dayanır .

Bir operatör yerine gerçekten bir yönteme ihtiyacınız varsa (örneğin, key=çok tuhaf bir tür için biraz garip yapmak ...?), Bu olurdu 'haystack'.__contains__. Ancak örneğiniz bir kullanımda olduğundan if, sanırım ;-) demek istediğinizi gerçekten kastetmiyorsunuz. Özel yöntemleri doğrudan kullanmak iyi bir form değildir (ne okunabilir ne de verimli) - bunun yerine, onlara delege olan operatörler ve yerleşikler aracılığıyla kullanılması amaçlanmıştır.


55

in Python dizeleri ve listeleri

İşte inyöntem hakkında kendileri için konuşan birkaç yararlı örnek :

"foo" in "foobar"
True

"foo" in "Foobar"
False

"foo" in "Foobar".lower()
True

"foo".capitalize() in "Foobar"
True

"foo" in ["bar", "foo", "foobar"]
True

"foo" in ["fo", "o", "foobar"]
False

["foo" in a for a in ["fo", "o", "foobar"]]
[False, False, True]

Uyarı. Listeler yinelenebilirdir ve inyöntem yalnızca dizgilere değil yinelemelere de uygulanır.


1
Listeden herhangi birini tek bir dizede aramak için liste değiştirilebilir mi? Ör: ["bar", "foo", "foobar"] in "foof"?
CaffeinatedCoder

1
@CaffeinatedCoder, hayır, bu iç içe yineleme gerektirir. En iyisi listeye "|" .join (["bar", "foo", "foobar"]) boruları ile katılarak ve bunun dışında bir normal ifadeyi derleyerek ve ardından "foof" ile eşleştirerek yapılır
firelynx

2
any (["bar", "foo", "foobar"]] içindeki x için "foof" içinde x)
Izaak Weiss

1
@IzaakWeiss Bir astarınız çalışır, ancak çok okunabilir değildir ve iç içe yineleme yapar. Bunu
yapmamaya

1
@ PiyushS.Wanare karmaşıklık ile ne demek istiyorsun? Normal ifade ile "WTF / dak" çok daha yüksektir.
firelynx

42

Memnun kalırsanız "blah" in somestringancak bir işlev / yöntem çağrısı olmasını istiyorsanız, muhtemelen bunu yapabilirsiniz

import operator

if not operator.contains(somestring, "blah"):
    continue

Python Tüm operatörler az ya da çok bulunabilir olabilir operatör modülü dahil in.


40

Görünüşe göre vektörel karşılaştırma için benzer bir şey yok. Bunu yapmanın bariz bir Python yolu:

names = ['bob', 'john', 'mike']
any(st in 'bob and john' for st in names) 
>> True

any(st in 'mary and jane' for st in names) 
>> False

1
Çünkü atomik değişkenlerden bir Ürün yaratmanın bajillion yolları vardır. Bunları bir demet halinde, bir listede (Kartezyen Ürünlerin formlarıdır ve zımni bir sırayla gelir) doldurabilir veya bir sınıfın özellikleri (önsel sipariş yok) veya sözlük değerleri olarak adlandırılabilir veya bir dizin veya her neyse. Bir 'kapsayıcı' veya 'bağlamda' bir şeyi benzersiz bir şekilde tanımlayabildiğinizde (iter veya getitem), bu 'kapsayıcıyı' bir tür vektör olarak görebilir ve üzerinde ikili ops tanımlayabilirsiniz. en.wikipedia.org/wiki/…
Niriel

inListelerle birlikte kullanılmaması gereken hiçbir şeye değmez , çünkü elementlerin doğrusal bir taramasını yapar ve karşılaştırıldığında yavaştır. Bunun yerine, özellikle üyelik testleri tekrar tekrar yapılacaksa bir set kullanın.
cs95

22

Kullanabilirsiniz y.count().

Bir alt dizenin bir dizede kaç kez göründüğünün tamsayı değerini döndürür.

Örneğin:

string.count("bah") >> 0
string.count("Hello") >> 1

8
sadece orada olup olmadığını kontrol etmek istediğinizde bir dize saymak pahalıdır ...
Jean-François Fabre

3
2010'dan itibaren orijinal yayında bulunan yöntemler, bu yüzden topluluktan fikir birliği ile onları düzenledim (bkz meta meta meta.stackoverflow.com/questions/385063/… )
Jean-François Fabre

17
Hayır. Demek istediğim, "neden 9 yıl önce diğerleriyle aynı şeyi cevaplamak"?
Jean-François Fabre


2
o zaman onu kaldırma yetkiniz varsa, onu kaldırın, başka ne yapmanız gerekiyorsa ve devam edin. IMO bu cevap, kullanıcılardan alınan oylarla yansıtılan değer katar.
Brandon Bailey

20

İşte cevabınız:

if "insert_char_or_string_here" in "insert_string_to_search_here":
    #DOSTUFF

Yanlış olup olmadığını kontrol etmek için:

if not "insert_char_or_string_here" in "insert_string_to_search_here":
    #DOSTUFF

VEYA:

if "insert_char_or_string_here" not in "insert_string_to_search_here":
    #DOSTUFF

8

Oluşumları almak için düzenli ifadeler kullanabilirsiniz:

>>> import re
>>> print(re.findall(r'( |t)', to_search_in)) # searches for t or space
['t', ' ', 't', ' ', ' ']
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.