Python 有字符串“contains”子字符串方法吗?

Does Python have a string 'contains' substring method?

提问人:Blankman 提问时间:8/9/2010 最后编辑:Peter MortensenBlankman 更新时间:11/1/2023 访问量:6558623

问:

这个问题的答案是社区的努力。编辑现有答案以改进此帖子。它目前不接受新的答案或交互。

我在 Python 中寻找 or 方法。string.containsstring.indexof

我想做:

if not somestring.contains("blah"):
   continue
python string 子字符串 包含

评论


答:

904赞 eldarerathis 8/9/2010 #1

如果只是一个子字符串搜索,则可以使用 .string.find("substring")

不过,您必须小心 findindexin,因为它们是子字符串搜索。换句话说,这:

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

它将打印类似,将计算为 .这可能是也可能不是你想要的。Found 'is' in the string.if "is" in s:True

评论

97赞 aaronasterling 8/9/2010
+1 用于突出显示子字符串搜索中涉及的陷阱。显而易见的解决方案是,它将按照(可能)预期的方式返回。if ' is ' in s:False
135赞 Bob 11/8/2012
@aaronasterling 这是显而易见的,但并不完全正确。如果您有标点符号,或者它位于开头或结尾怎么办?资本化呢?更好的是不区分大小写的正则表达式搜索(单词边界)。\bis\b
3赞 uh_big_mike_boi 2/18/2022
为什么这不是OP想要的
3赞 TheTechRobo the Nerd 6/20/2022
@uh_big_mike_boi 子字符串搜索的问题在于,在此示例中,您要查找的单词位于“This be a string”中。由于 in 的计算结果为 True,因此计算结果为 True。这对于搜索单词的程序(例如脏话过滤器)不利(例如,对“ass”的哑词检查也会捕获“grass”)。isThis
8305赞 Michael Mrozek 8/9/2010 #2

使用 in 运算符

if "blah" not in somestring: 
    continue

注意:这区分大小写。

评论

8赞 Kite 4/14/2023
注意:这区分大小写。
197赞 Alex Martelli 8/9/2010 #3

if needle in haystack:正如@Michael所说,它是正常的用法——它依赖于 in 运算符,比方法调用更具可读性和更快。

如果你真的需要一种方法而不是一个运算符(例如,为一个非常奇特的分类做一些奇怪的事情......?),那将是“大海捞针”.__contains__。但是,由于您的示例用于 ,我猜您所说的并不是真的;直接使用特殊方法不是好的形式(也不是可读的,也不是有效的)——它们应该通过委托给它们的运算符和内置函数来使用。key=if

评论

2赞 SO_fix_the_vote_sorting_bug 11/12/2021
比方法调用快多少?
516赞 Russia Must Remove Putin 11/26/2014 #4

Python 有包含子字符串方法的字符串吗?

99% 的用例将使用关键字 , 进行覆盖,该关键字返回 或 :inTrueFalse

'substring' in any_string

对于获取索引的用例,请使用(失败时返回 -1,并具有可选的位置参数):str.find

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

或(类似,但在失败时引发 ValueError):str.indexfind

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__

“contains” 方法实现 的行为。这个例子,in

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

返回。您也可以从超字符串的实例中调用此函数:True

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

但不要。以下划线开头的方法在语义上被视为非公共方法。使用它的唯一原因是在实现或扩展 and 功能时(例如,如果子类化):innot instr

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

不要使用和测试“包含”findindex

请勿使用以下字符串方法来测试“contains”:

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

如果你真的是想说,那就说出来。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

因此,我们看到必须单独查找该方法,然后从 Python 虚拟机调用该方法 - 这应该充分解释了差异。.__contains__

评论

11赞 coderforlife 6/10/2015
为什么要避免和?你怎么会建议别人找到子字符串的索引,而不仅仅是它是否存在?(或者你的意思是避免使用它们来代替包含 - 所以不要用代替?str.indexstr.finds.find(ss) != -1ss in s
4赞 Russia Must Remove Putin 6/10/2015
正是如此,尽管使用这些方法背后的意图可以通过优雅地使用模块来更好地解决。我还没有在我编写的任何代码中找到 str.index 或 str.find 自己的用途。re
2赞 cs95 6/5/2019
请将您的答案扩展到不要使用的建议()。不寒而栗str.countstring.count(something) != 0
1赞 jpmc26 8/19/2019
操作员模块版本的性能如何?
1赞 Russia Must Remove Putin 8/19/2019
@jpmc26它与上面相同 - 但它周围有一个堆栈框架,所以它比这更慢:github.com/python/cpython/blob/3.7/Lib/operator.py#L153in_
26赞 rassa45 5/26/2015 #5

这是你的答案:

if "insert_char_or_string_here" in "insert_string_to_search_here":
    #DOSTUFF

要检查它是否为 false:

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

BRW公司

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

评论

1赞 gerrit 10/18/2021
PEP 8 更喜欢“if x not in y”而不是“if not x in y”。
53赞 Ufos 7/17/2015 #6

因此,显然没有类似的向量比较。一个明显的 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

评论

1赞 Niriel 8/10/2015
那是因为有无数种方法可以从原子变量创建产品。你可以把它们塞进一个元组、一个列表(它们是笛卡尔积的形式,带有隐含的顺序),或者它们可以被命名为类的属性(没有先验顺序)或字典值,或者它们可以是目录中的文件,或者其他什么。每当您可以在“容器”或“上下文”中唯一标识(iter 或 getitem)某些内容时,您都可以将该“容器”视为一种向量,并在其上定义二进制运算。en.wikipedia.org/wiki/......
2赞 cs95 6/5/2019
不值一提,不应该与列表一起使用,因为它对元素进行线性扫描并且比较慢。请改用集合,尤其是在重复进行成员资格测试时。in
137赞 firelynx 4/29/2017 #7

inPython 字符串和列表

以下是一些有用的示例,这些示例说明了该方法的正确性: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

如果您想以更模糊的方式比较字符串以衡量它们的“相似”程度,请考虑使用 Levenshtein 包

这是一个显示其工作原理的答案。

56赞 Jeffrey04 3/28/2018 #8

如果你对它感到满意,但希望它是一个函数/方法调用,你可以这样做"blah" in somestring

import operator

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

Python 中的所有运算符都可以在运算符模块中找到,包括 .in

12赞 Muskovets 11/23/2018 #9

您可以使用正则表达式来获取出现次数:

>>> import re
>>> print(re.findall(r'( |t)', to_search_in)) # searches for t or space
['t', ' ', 't', ' ', ' ']

评论

0赞 Sadegh Moayedizadeh 8/8/2023
就时间复杂度而言,它实际上效率较低。您最好使用运算符。但这是一个有趣的解决方案。如果您坚持使用 ,最好用作布尔值。inrere.match
33赞 Brandon Bailey 2/6/2019 #10

您可以使用 .y.count()

它将返回子字符串在字符串中出现的次数的整数值。

例如:

string.count("bah")   # gives 0
string.count("Hello") # gives 1

评论

13赞 Jean-François Fabre 5/16/2019
当您只想检查它是否存在时,计算字符串的成本很高......
1赞 Brandon Bailey 6/5/2019
我同意,我有一个深入的答案,提出了 3 种可能的解决方案。但让-弗朗索瓦·法布尔(Jean-Francois Fabre)将其改为现在的样子。不知道他为什么会这样改变它。
8赞 rsandwick3 3/28/2020
几乎可以肯定,右移不是你想在这里做的事情。
1赞 Chr1s 12/15/2022
这不是问题的答案。这绝不是一种确定一个字符串是否在另一个字符串中的惯用方法
0赞 smci 9/16/2023
@rsandwick3:我认为OP只表示“>>”来表示“给出结果”,例如“->”或“==>”。我编辑澄清。