Есть ли в Python строковый метод подстроки?

avatar
Blankman
9 августа 2010 в 02:52
5229494
10
3596

Я ищу метод string.contains или string.indexof в Python.

Я хочу сделать:

if not somestring.contains("blah"):
   continue
Источник

Ответы (10)

avatar
Michael Mrozek
9 августа 2010 в 02:56
7363

Вы можете использовать in оператор:

if "blah" not in somestring: 
    continue
BallpointBen
17 августа 2018 в 07:02
323

Под капотом Python будет использовать __contains__(self, item), __iter__(self) и __getitem__(self, key) в указанном порядке, чтобы определить, находится ли элемент в заданном контейнере. Реализуйте хотя бы один из этих методов, чтобы сделать in доступным для вашего пользовательского типа.

Big Pumpkin
10 октября 2018 в 22:44
50

Просто убедитесь, что somestring не будет None. В противном случае вы получите TypeError: argument of type 'NoneType' is not iterable

Trenton
13 ноября 2018 в 21:41
14

FWIW, это идиоматический способ достичь указанной цели.

Sam Chats
18 декабря 2018 в 20:23
11

Для строк, использует ли оператор Python in алгоритм Рабина-Карпа?

Kaz
12 февраля 2019 в 20:24
2

Это непоследовательно и некрасиво в коде вроде ".so." in filename or filename.endswith(".blah").

Kaz
14 февраля 2019 в 17:54
0

^ Я имел в виду filename.endswith(".so").

Christoph Burschka
28 февраля 2019 в 15:34
7

@SamChats см. coderhelper.com/questions/18139660/… для получения подробной информации о реализации (в CPython; а также спецификация языка не требует здесь какого-либо конкретного алгоритма).

Veky
20 июля 2019 в 20:28
4

@Kaz Это должно быть некрасиво, поскольку вы думаете на неправильном уровне абстракции. С другой стороны, '.so' in filepath.suffixes довольно красиво и ясно говорит о том, чем вы действительно хотите заниматься.

Kaz
20 июля 2019 в 21:24
0

@Veky Суффиксы файлов не являются уровнем абстракции; они просто взлом.

Veky
22 июля 2019 в 02:33
2

@Kaz Возможно, но вы можете объяснить, почему вам нужно проверять такое странное условие на имя файла? Для меня это имеет смысл только в том случае, если вы хотите проверить, есть ли в имени определенный суффикс - но, возможно, я недостаточно изобретателен. :-)

Fred vdP
30 августа 2019 в 10:29
4

Эта перегрузка Python in для строк кажется мне немного непоследовательной и уродливой (хотя, несомненно, практичной), поскольку я привык интерпретировать «in» как «является элементом», и это здесь не работает - сравните "blah" in mystring с "blah" in list(mystring) ...

Veky
17 сентября 2019 в 08:50
0

@FredvdP это было так давно. Предыдущие версии Python имели только in для одноэлементных строк. Вам нужно было использовать .find для подстрок. Но, конечно, это было намного практичнее.

Jean-François Fabre
22 сентября 2019 в 17:10
0

err: "вы можете использовать оператор" in ", а затем пример с оператором" not in ". Может быть, это следует изменить.

avatar
Brandon Bailey
6 февраля 2019 в 11:06
30

Вы можете использовать y.count().

Он вернет целочисленное значение количества раз, когда подстрока появляется в строке.

Например:

string.count("bah") >> 0
string.count("Hello") >> 1
Jean-François Fabre
16 мая 2019 в 05:53
10

подсчет строки обходится дорого, если вы просто хотите проверить , есть ли она там ...

Brandon Bailey
16 мая 2019 в 09:24
0

вот почему я предоставил несколько методов

Jean-François Fabre
16 мая 2019 в 11:38
3

методы, которые существуют в исходном сообщении от 2010 года, поэтому я закончил их редактированием с согласия сообщества (см. мета-сообщение meta.coderhelper.com/questions/385063/…)

Brandon Bailey
16 мая 2019 в 11:46
0

Ну, есть только конечное количество способов достичь того, о чем просил OP. Планируете ли вы разработать язык Python и внедрить НОВЫЙ метод запросов к подстрокам?

Jean-François Fabre
16 мая 2019 в 11:48
17

нет. Я хочу сказать, «зачем отвечать на то же самое, что и другие 9 лет назад»?

Brandon Bailey
16 мая 2019 в 11:54
1

Я опубликовал 3 действительных метода для достижения цели OP и других зрителей. Учитывая характер предоставленной информации, неразумно ожидать, что все ответы будут на 100% уникальными. В принятом ответе не было двух других методов, которые я предоставил, поэтому я расширил список допустимых ответов, чтобы помочь всем, кто сталкивается с этой проблемой. Почему ты дышишь, когда уже есть люди, которые дышат?

Jean-François Fabre
16 мая 2019 в 11:55
10

потому что я модерирую сайт ... Я задал вопрос на meta meta.coderhelper.com/questions/385063/…

Brandon Bailey
16 мая 2019 в 12:06
2

затем, если у вас есть полномочия удалить его, удалите его, иначе сделайте то, что вы должны, и двигайтесь дальше. ИМО, этот ответ добавляет ценность, что отражается в голосах пользователей.

Brandon Bailey
5 июня 2019 в 09:34
1

Я согласен, у меня был подробный ответ, в котором было предложено 3 возможных решения. но Жан-Франсуа Фабр изменил это положение, чтобы оно стало тем, чем оно является сейчас. Не уверен, зачем он это так изменил.

rsandwick3
28 марта 2020 в 03:53
4

Сдвиг вправо - это почти наверняка не то, чем вы хотите здесь заниматься.

avatar
Muskovets
23 ноября 2018 в 07:15
10

Вы можете использовать регулярные выражения для получения вхождений:

>>> import re
>>> print(re.findall(r'( |t)', to_search_in)) # searches for t or space
['t', ' ', 't', ' ', ' ']
avatar
Jeffrey04
28 марта 2018 в 09:59
48

Если вас устраивает "blah" in somestring, но вы хотите, чтобы это был вызов функции / метода, вы, вероятно, можете сделать это

import operator

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

Все операторы в Python можно более или менее найти в модуле операторов , включая in.

avatar
firelynx
28 апреля 2017 в 18:52
83

in Строки и списки Python

Вот несколько полезных примеров, которые говорят сами за себя относительно метода in:

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

Предупреждение. Списки являются итерируемыми, и метод in воздействует на итерируемые объекты, а не только на строки.

avatar
Ufos
17 июля 2015 в 13:19
43

Очевидно, ничего подобного для векторного сравнения нет. Очевидный способ Python сделать это:

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
Niriel
10 августа 2015 в 09:50
1

Это потому, что существует миллионы способов создать продукт из атомарных переменных. Вы можете поместить их в кортеж, список (которые являются формами декартовых произведений и имеют подразумеваемый порядок), или они могут быть названы свойствами класса (без априорного порядка) или значениями словаря, или они могут быть файлами в каталог или что-то еще. Всякий раз, когда вы можете однозначно идентифицировать (iter или getitem) что-то в «контейнере» или «контексте», вы можете видеть этот «контейнер» как своего рода вектор и определять на нем бинарные операции. en.wikipedia.org/wiki/…

cs95
5 июня 2019 в 03:06
0

Ничего не стоит, если in не следует использовать со списками, потому что он выполняет линейное сканирование элементов и медленно сравнивается. Вместо этого используйте набор, особенно если тесты на членство нужно делать повторно.

avatar
ytpillai
25 мая 2015 в 22:50
23

Вот ваш ответ:

if "insert_char_or_string_here" in "insert_string_to_search_here":
    #DOSTUFF

Для проверки ложности:

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

ИЛИ:

if "insert_char_or_string_here" not in "insert_string_to_search_here":
    #DOSTUFF
Arthur Bowers
31 марта 2021 в 12:37
0

Интересно знать, что вы могли бы сделать, если бы не так хорошо, как если бы не внутри.

avatar
Aaron Hall
25 ноября 2014 в 22:33
344

Есть ли в Python строка, содержащая метод подстроки?

99% вариантов использования будут охвачены с помощью ключевого слова in, которое возвращает True или False:

'substring' in any_string

В случае использования для получения индекса используйте str.find (который возвращает -1 в случае ошибки и имеет необязательные позиционные аргументы):

start = 0
stop = len(any_string)
any_string.find('substring', start, stop)

или str.index (например, find, но вызывает ValueError при сбое):

start = 100 
end = 1000
any_string.index('substring', start, end)

Пояснение

Используйте оператор сравнения in, потому что

  1. язык предполагает его использование, и
  2. другие программисты Python ожидают, что вы будете его использовать.
>>> 'foo' in '**foo**'
True

Противоположное (дополнение), которое задано в исходном вопросе, это not in:

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

Семантически то же самое, что и not 'foo' in '**foo**', но он гораздо более читабелен и явно предусмотрен в языке как улучшение читаемости.

Избегайте использования __contains__

Метод "содержит" реализует поведение для in. В этом примере:

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

возвращает True. Вы также можете вызвать эту функцию из экземпляра суперстроки:

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

Но не надо. Методы, начинающиеся с подчеркивания, считаются семантически закрытыми. Единственная причина использовать это - при реализации или расширении функций in и not in (например, при создании подкласса str):

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

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

и теперь:

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

Не используйте find и index для проверки "содержит"

Не используйте следующие строковые методы для проверки "содержит":

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

В других языках может не быть методов для непосредственного тестирования подстрок, поэтому вам придется использовать эти типы методов, но с Python гораздо эффективнее использовать оператор сравнения in.

Кроме того, это не прямая замена для in. Возможно, вам придется обработать исключение или случаи -1, и если они вернут 0 (поскольку они нашли подстроку в начале), логическая интерпретация будет False вместо True.

Если вы действительно имеете в виду not any_string.startswith(substring), то скажите это.

Сравнение производительности

Мы можем сравнить различные способы достижения одной и той же цели.

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'))),
}

И теперь мы видим, что использование in намного быстрее, чем другие. Лучше меньше времени на выполнение эквивалентной операции:

>>> 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}

Как может in быть быстрее, чем __contains__, если in использует __contains__?

Хороший дополнительный вопрос.

Разберем функции интересующими методами:

>>> from dis import dis
>>> dis(lambda: 'a' in 'b')
  1           0 LOAD_CONST               1 ('a')
              2 LOAD_CONST               2 ('b')
              4 COMPARE_OP               6 (in)
              6 RETURN_VALUE
>>> dis(lambda: 'b'.__contains__('a'))
  1           0 LOAD_CONST               1 ('b')
              2 LOAD_METHOD              0 (__contains__)
              4 LOAD_CONST               2 ('a')
              6 CALL_METHOD              1
              8 RETURN_VALUE

, поэтому мы видим, что метод .__contains__ нужно искать отдельно, а затем вызывать из виртуальной машины Python - это должно адекватно объяснить разницу.

coderforlife
10 июня 2015 в 03:35
8

Почему следует избегать str.index и str.find? Как еще вы могли бы предложить кому-то найти индекс подстроки, а не просто узнать, существует она или нет? (или вы имели в виду не использовать их вместо содержит - поэтому не используйте s.find(ss) != -1 вместо ss in s?)

Aaron Hall
10 июня 2015 в 03:39
3

Именно так, хотя цель использования этих методов может быть лучше решена за счет элегантного использования модуля re. Я еще не нашел применения str.index или str.find в любом написанном мной коде.

cs95
5 июня 2019 в 03:05
0

Дополните свой ответ советом не использовать также str.count (string.count(something) != 0). дрожь

jpmc26
18 августа 2019 в 19:30
0

Как работает модуль operator версии?

Aaron Hall
18 августа 2019 в 23:34
0

@ jpmc26 это то же самое, что и in_ выше, но с рамкой стека вокруг него, поэтому он медленнее, чем этот: github.com/python/cpython/blob/3.7/Lib/operator.py#L153

Rich Lysakowski PhD
29 августа 2020 в 14:12
1

Это отличный ответ на универсальную потребность в Python. Спасибо за подробные объяснения!

Lou
16 декабря 2020 в 10:49
0

Я чувствую, что это должен быть принятый ответ ...

burningfennec
30 мая 2021 в 07:59
0

Как in может быть быстрее, чем __contains__, если in использует __contains__?

Aaron Hall
30 мая 2021 в 22:35
1

@burningfennec Я ответил на ваш следующий вопрос в конце ответа выше.

avatar
Alex Martelli
9 августа 2010 в 03:19
186

if needle in haystack: - это нормальное использование, как говорит @Michael - оно основывается на операторе in, более читаемом и быстром, чем вызов метода.

Если вам действительно нужен метод вместо оператора (например, чтобы сделать какой-то странный key= для очень своеобразной сортировки ...?), Это будет 'haystack'.__contains__. Но поскольку ваш пример предназначен для использования в if, я думаю, вы на самом деле не имеете в виду то, что говорите ;-). Непосредственное использование специальных методов не является хорошей формой (ни читабельностью, ни эффективностью) - вместо этого они предназначены для использования через операторы и встроенные функции, которые им делегируют.

avatar
eldarerathis
9 августа 2010 в 02:55
787
aaronasterling
9 августа 2010 в 03:22
86

+1 для выделения ошибок, связанных с поиском подстроки. очевидным решением является if ' is ' in s:, которое вернет False, как (вероятно) ожидается.

Bob
8 ноября 2012 в 00:07
114

@aaronasterling Возможно, это очевидно, но не совсем правильно. Что делать, если у вас есть знаки препинания или они стоят в начале или в конце? А как насчет использования заглавных букв? Лучше было бы поиск по регулярному выражению без учета регистра для \bis\b (границы слов).