Odpowiedzi:
Możesz użyć in
operatora :
if "blah" not in somestring:
continue
TypeError: argument of type 'NoneType' is not iterable
in
operator Python używa algorytmu Rabin-Carp?
Jeśli jest to tylko wyszukiwanie podciągów, możesz użyć string.find("substring")
.
Trzeba być trochę ostrożny z find
, index
i in
choć są one podciąg wyszukiwania. Innymi słowy, to:
s = "This be a string"
if s.find("is") == -1:
print("No 'is' here!")
else:
print("Found 'is' in the string.")
Wypisałby się Found 'is' in the string.
podobnie, if "is" in s:
oceniałby True
. To może być lub nie być to, czego chcesz.
if ' is ' in s:
co powróci, False
jak się spodziewano (prawdopodobnie).
\bis\b
(granice słów).
' is '
, w szczególności, że nie zostanie on złapany This is, a comma'
lub 'It is.'
.
s.split(string.punctuation + string.whitespace)
choć raz; split
nie jest jak rodzina funkcji strip
/ rstrip
/ lstrip
, dzieli się tylko wtedy, gdy widzi wszystkie znaki separatora, w sposób ciągły, w dokładnie takiej kolejności. Jeśli chcesz podzielić na klasy znaków, wrócisz do wyrażeń regularnych (w tym momencie wyszukiwanie r'\bis\b'
bez podziału jest łatwiejszą i szybszą drogą).
'is' not in (w.lower() for w in s.translate(string.maketrans(' ' * len(string.punctuation + string.whitespace), string.punctuation + string.whitespace)).split()
- ok, punkt wzięty. To jest teraz śmieszne ...
Czy Python ma ciąg zawierający metodę podciągów?
Tak, ale Python ma operator porównania, którego należy użyć zamiast tego, ponieważ język zamierza go używać, a inni programiści oczekują, że będziesz go używać. To słowo kluczowe jest in
używane jako operator porównania:
>>> 'foo' in '**foo**'
True
Przeciwnie (uzupełnienie), o które prosi pierwotne pytanie, jest not in
:
>>> 'foo' not in '**foo**' # returns False
False
Jest to semantycznie to samo, not 'foo' in '**foo**'
ale o wiele bardziej czytelne i wyraźnie przewidziane w języku jako poprawa czytelności.
__contains__
, find
orazindex
Zgodnie z obietnicą, oto contains
metoda:
str.__contains__('**foo**', 'foo')
zwraca True
. Możesz także wywołać tę funkcję z instancji superstringu:
'**foo**'.__contains__('foo')
Ale nie rób tego. Metody rozpoczynające się od podkreślenia są uważane za semantycznie prywatne. Jedynym powodem, dla którego można to wykorzystać, jest rozszerzenie funkcji in
i not in
(np. W przypadku podklasy 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')
i teraz:
>>> 'substring' in ns
testing if "substring" in "a string with a substring inside"
True
Unikaj również następujących metod ciągu:
>>> '**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
Inne języki mogą nie mieć żadnych metod bezpośredniego testowania podciągów, więc musisz użyć tego rodzaju metod, ale w Pythonie znacznie bardziej wydajne jest użycie in
operatora porównania.
Możemy porównać różne sposoby osiągnięcia tego samego celu.
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'))),
}
A teraz widzimy, że używanie in
jest znacznie szybsze niż inne. Im mniej czasu na wykonanie równoważnej operacji, tym lepiej:
>>> 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}
str.index
i str.find
? Jak inaczej zasugerowałbyś komuś znalezienie indeksu podciągów zamiast tego, czy istnieje? (czy miałeś na myśli unikanie ich zamiast zawiera - więc nie używaj s.find(ss) != -1
zamiast ss in s
?)
re
modułu. Nie znalazłem jeszcze zastosowania dla str.index lub str.find siebie w żadnym kodzie, który napisałem.
str.count
również ( string.count(something) != 0
). Dreszcz
operator
wersja modułu ?
in_
powyżej - ale z ramką stosu, więc jest wolniejszy: github.com/python/cpython/blob/3.7/Lib/operator.py#L153
if needle in haystack:
jest normalnym zastosowaniem, jak mówi @Michael - zależy od in
operatora, jest bardziej czytelny i szybszy niż wywołanie metody.
Jeśli naprawdę potrzebujesz metody zamiast operatora (np. Aby zrobić coś dziwnego key=
dla bardzo osobliwego rodzaju ...?), Byłoby to możliwe 'haystack'.__contains__
. Ale ponieważ twój przykład jest przeznaczony do użycia if
, myślę, że tak naprawdę nie masz na myśli tego, co mówisz ;-). Nie jest dobrą formą (ani czytelną, ani wydajną) używanie specjalnych metod bezpośrednio - są one przeznaczone do użycia przez operatorów i wbudowane w nie funkcje, które je delegują.
in
Ciągi i listy w języku PythonOto kilka przydatnych przykładów, które mówią same za siebie w odniesieniu do in
metody:
"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]
Zastrzeżenie Listy są iterowalne, a in
metoda działa na iterowalne, a nie tylko na ciągi znaków.
["bar", "foo", "foobar"] in "foof"
?
Jeśli jesteś zadowolony, "blah" in somestring
ale chcesz, aby było to wywołanie funkcji / metody, prawdopodobnie możesz to zrobić
import operator
if not operator.contains(somestring, "blah"):
continue
Wszystkich operatorów w Pythonie można mniej więcej znaleźć w module operatora, w tym in
.
Najwyraźniej więc nie ma nic podobnego w porównaniu wektorowym. Oczywistym sposobem na zrobienie tego byłoby:
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
in
czego nie należy używać z listami, ponieważ wykonuje liniowy skan elementów i jest powolny w porównaniu. Zamiast tego użyj zestawu, szczególnie jeśli testy członkostwa mają być powtarzane.
Możesz użyć y.count()
.
Zwraca wartość całkowitą liczby przypadków, gdy podciąć pojawia się w ciągu.
Na przykład:
string.count("bah") >> 0
string.count("Hello") >> 1
Oto twoja odpowiedź:
if "insert_char_or_string_here" in "insert_string_to_search_here":
#DOSTUFF
Aby sprawdzić, czy jest to fałsz:
if not "insert_char_or_string_here" in "insert_string_to_search_here":
#DOSTUFF
LUB:
if "insert_char_or_string_here" not in "insert_string_to_search_here":
#DOSTUFF
__contains__(self, item)
,__iter__(self)
iw__getitem__(self, key)
tej kolejności, aby ustalić, czy element leży w danym zawiera. Zaimplementuj co najmniej jedną z tych metod, abyin
udostępnić niestandardowy typ.