re.search 和 re.match 有什么区别?

What is the difference between re.search and re.match?

提问人:Daryl Spitzer 提问时间:10/8/2008 最后编辑:cottontailDaryl Spitzer 更新时间:6/5/2023 访问量:409057

问:

Python 模块中的 and 函数有什么区别?search()match()re

我已经阅读了 Python 2 文档(Python 3 文档),但我似乎从不记得它。

Python 正则表达式 搜索 字符串匹配

评论

1赞 Andy Lester 11/14/2022
我记得的是,“搜索”在我脑海中唤起了一个探险家的形象,他用双筒望远镜向远处搜索,就像在远处搜索到绳子的尽头一样。search

答:

651赞 nosklo 10/8/2008 #1

re.match定位在字符串的开头。这与换行符无关,因此它与在模式中使用不同。^

正如 re.match 文档所说:

如果字符串开头的零个或多个字符与正则表达式模式匹配,则返回 相应的实例。 如果字符串不返回,则返回 匹配模式;请注意,这是 与零长度匹配不同。MatchObjectNone

注意:如果您想找到匹配项 在字符串中的任何位置,请改用。search()

re.search搜索整个字符串,如文档所述

扫描字符串以查找 正则表达式的位置 pattern 生成匹配项,并返回 相应的实例。 如果 字符串与模式匹配;请注意, 这与找到 在 字符串。MatchObjectNone

因此,如果您需要在字符串的开头匹配,或者要匹配整个字符串,请使用 .它更快。否则使用 .matchsearch

该文档有一个用于匹配搜索的特定部分,其中还涵盖了多行字符串:

Python 提供了两种不同的原语 基于常规的操作 表达式:仅在字符串的开头检查匹配项, 而检查字符串中任何位置的匹配项(这就是什么 Perl 默认这样做)。matchsearch

请注意,即使使用正则表达式也可能有所不同 开头为 : 仅匹配 在字符串的开头,或立即处于模式 跟在换行符后面。“” 仅当模式 无论模式如何,在字符串的开头都匹配,或者在开头匹配 由可选参数给出的位置,而不管 换行符在它前面。matchsearch'^''^'MULTILINEmatchpos

现在,说得够多了。是时候看一些示例代码了:

# example code:
string_with_newlines = """something
someotherthing"""

import re

print re.match('some', string_with_newlines) # matches
print re.match('someother', 
               string_with_newlines) # won't match
print re.match('^someother', string_with_newlines, 
               re.MULTILINE) # also won't match
print re.search('someother', 
                string_with_newlines) # finds something
print re.search('^someother', string_with_newlines, 
                re.MULTILINE) # also finds something

m = re.compile('thing$', re.MULTILINE)

print m.match(string_with_newlines) # no match
print m.match(string_with_newlines, pos=4) # matches
print m.search(string_with_newlines, 
               re.MULTILINE) # also matches

评论

36赞 Alby 7/23/2014
那么,为什么有人会使用有限而不是更通用呢?是为了速度吗?matchsearch
25赞 Ivan Bilan 5/24/2016
@Alby匹配比搜索快得多,所以你可以做正则表达式.match((.*?)而不是做regex.search(“word”)字(.*?))如果您正在处理数百万个样品,则可以获得大量性能。
48赞 Sammaron 9/16/2016
嗯,这很愚蠢。为什么叫它?用不直观的名称来植入 API 以迫使我阅读文档是一种聪明的策略吗?我还是不会这样做!反叛!match
2赞 baptx 1/22/2019
@ivan_bilan使用相同的正则表达式时看起来比搜索有点,但根据性能测试,您的示例似乎是错误的:stackoverflow.com/questions/180986/...matchfaster
2赞 Zitao Wang 8/19/2019
当使用以 '^' 开头且未指定且未指定的正则表达式时,是否与 (produce the same result) 相同?MULTILINEmatchsearch
20赞 cschol 10/8/2008 #2

re.match 尝试匹配字符串开头的模式。re.search 尝试匹配整个字符串的模式,直到找到匹配项。

59赞 xilun 10/8/2008 #3

re.search 在整个字符串中搜索模式,而不搜索模式;如果没有,它别无选择,只能在字符串的开头匹配它。re.match

评论

5赞 Smit Johnth 7/15/2015
为什么在开始时匹配,而不是直到字符串结束(在 phyton 3.4 中)?fullmatch
141赞 Dhanasekaran Anbalagan 12/31/2011 #4

search⇒字符串中的任意位置找到某些内容并返回匹配对象。

match⇒在字符串的开头找到一些东西并返回一个匹配对象。

41赞 ldR 7/30/2015 #5

您可以参考下面的示例来了解 和 re.search 的工作原理re.match

a = "123abc"
t = re.match("[a-z]+",a)
t = re.search("[a-z]+",a)

re.match将返回,但将返回。nonere.searchabc

评论

5赞 SanD 3/1/2017
只想补充一点,搜索将返回_sre。SRE_Match对象(如果未找到,则为 None)。要获得 'abc',您需要调用 t.group()
40赞 CODE-REaD 5/21/2016 #6

区别在于,re.match() 误导了任何习惯于 Perlgrepsed 正则表达式匹配的人,而 re.search() 则不会。

更清醒的是,正如约翰·库克(John D. Cook)所说,“表现得好像每个模式都有^前缀。换句话说,等于 .因此,它锚定了图案的左侧。但它也不能锚定模式的右侧:这仍然需要终止 。re.match()re.match('pattern')re.search('^pattern')$

坦率地说,鉴于上述情况,我认为应该弃用。我很想知道应该保留它的原因。re.match()

评论

5赞 JoelFan 6/28/2017
“behaves as if every pattern have ^ prepended.” 仅在不使用多行选项时才为 true。正确的陈述是“......有 \A 前缀”
103赞 Jeyekomon 4/8/2018 #7

match 比 search 快得多,所以你可以做 regex.match((.*?) 而不是做 regex.search(“word”)字(.*?))如果您正在处理数百万个样品,则可以获得大量性能。

@ivan_bilan在上面接受的答案下的这条评论让我思考这样的黑客是否真的在加速任何事情,所以让我们看看你真正会获得多少吨的性能。

我准备了以下测试套件:

import random
import re
import string
import time

LENGTH = 10
LIST_SIZE = 1000000

def generate_word():
    word = [random.choice(string.ascii_lowercase) for _ in range(LENGTH)]
    word = ''.join(word)
    return word

wordlist = [generate_word() for _ in range(LIST_SIZE)]

start = time.time()
[re.search('python', word) for word in wordlist]
print('search:', time.time() - start)

start = time.time()
[re.match('(.*?)python(.*?)', word) for word in wordlist]
print('match:', time.time() - start)

我做了 10 次测量(1M、2M、...、10M 字),得出了以下图:

match vs. search regex speedtest line plot

如您所见,搜索模式“python”比匹配模式更快'(.*?)python(.*?)'

Python 很聪明。避免试图变得更聪明。

评论

39赞 Robert Dodier 10/31/2018
+1 实际调查了旨在从表面上理解的陈述背后的假设 -- 谢谢。
2赞 baptx 1/22/2019
事实上,@ivan_bilan 的注释看起来是错误的,但如果你比较相同的正则表达式,该函数仍然比函数快。您可以通过比较来检查您的脚本(或者,如果您不阅读文档并且似乎不影响性能,则哪个相同但更容易理解)matchsearchre.search('^python', word)re.match('python', word)re.match('^python', word)
3赞 Jeyekomon 1/22/2019
@baptx 我不同意该函数通常更快的说法。当您想在字符串的开头搜索时,速度更快,当您想搜索整个字符串时,速度更快。这符合常识。这就是为什么@ivan_bilan错了——他过去常常在整个字符串中搜索。这就是为什么你是对的 - 你曾经在字符串的开头搜索。如果您不同意我的观点,请尝试找到正则表达式,因为它比它更快并且做同样的工作。matchmatchsearchmatchmatchmatchre.search('python', word)
0赞 Jeyekomon 1/22/2019
@baptx 此外,作为脚注,它比 稍快。必须如此。re.match('python')re.match('^python')
1赞 baptx 1/24/2019
@Jeyekomon是的,这就是我的意思,如果您想在字符串的开头进行搜索,函数会更快一些(例如,与使用函数在字符串开头查找单词相比)。但我觉得这很奇怪,如果你告诉函数在字符串的开头搜索,它应该和函数一样快。matchsearchre.search('^python', word)searchmatch
23赞 U13-Forward 10/31/2018 #8

更短:

  • search扫描整个字符串。

  • match仅扫描字符串的开头。

以下 Ex 说:

>>> a = "123abc"
>>> re.match("[a-z]+",a)
None
>>> re.search("[a-z]+",a)
abc

评论

1赞 noidentity63 1/5/2023
即使这里发布了大多数示例,我也很难将“字符串开头”的描述视为准确的陈述。我不知道,这似乎是武断的。我怎么知道字符串的开头“结束”在哪里?是通过换行符吗?因为根据这里的例子,“开始”只是表示第一个字符“1”。
1赞 Pall Arpad 6/20/2022 #9

快速回答

re.search('test', ' test')      # returns a Truthy match object (because the search starts from any index) 

re.match('test', ' test')       # returns None (because the search start from 0 index)
re.match('test', 'test')        # returns a Truthy match object (match at 0 index)
1赞 cottontail 6/5/2023 #10

re.match锚定在字符串的开头,同时扫描整个字符串。所以在下面的例子中,并匹配同样的东西。re.searchxy

x = re.match('pat', s)       # <--- already anchored at the beginning of string
y = re.search('\Apat', s)    # <--- match at the beginning

如果字符串不包含换行符,并且本质上是相同的;差异显示在多行字符串中。在以下示例中,永远不会匹配第二行,而可以使用正确的正则表达式(和标志)。\A^re.matchre.search

s = "1\n2"
re.match('2', s, re.M)       # no match
re.search('^2', s, re.M)     # match
re.search('\A2', s, re.M)    # no match  <--- mimics `re.match`

中还有另一个函数,它扫描整个字符串,因此它被锚定在字符串的开头和结尾。所以在下面的例子中,和 匹配同样的东西。rere.fullmatch()xyz

x = re.match('pat\Z', s)     # <--- already anchored at the beginning; must match end
y = re.search('\Apat\Z', s)  # <--- match at the beginning and end of string
z = re.fullmatch('pat', s)   # <--- already anchored at the beginning and end

根据 Jeyekomon 的回答(并使用他们的设置),使用 perfplot 库,我绘制了 timeit 测试的结果,该测试研究了:

  • 他们如何比较“模仿”?(第一图)re.searchre.match
  • 他们如何比较“模仿”?(第二图)re.matchre.search
  • 如果将相同的模式传递给他们,他们如何比较?(最后一幅图)

请注意,最后一个模式不会产生相同的输出(因为它锚定在字符串的开头)。re.match

performance plot

第一个图显示,如果像 一样使用,则速度更快。第二个图支持@Jeyekomon的答案,如果像 一样使用,则显示速度更快。最后一张图显示,如果它们扫描相同的模式,则两者之间几乎没有区别。matchsearchmatchsearchmatchsearch


用于生成性能图的代码。

import re
from random import choices
from string import ascii_lowercase
import matplotlib.pyplot as plt
from perfplot import plot

patterns = [
    [re.compile(r'\Aword'), re.compile(r'word')],
    [re.compile(r'word'), re.compile(r'(.*?)word')],
    [re.compile(r'word')]*2
]

fig, axs = plt.subplots(1, 3, figsize=(20,6), facecolor='white')
for i, (pat1, pat2) in enumerate(patterns):
    plt.sca(axs[i])
    perfplot.plot(
        setup=lambda n: [''.join(choices(ascii_lowercase, k=10)) for _ in range(n)],
        kernels=[lambda lst: [*map(pat1.search, lst)], lambda lst: [*map(pat2.match, lst)]],
        labels= [f"re.search(r'{pat1.pattern}', w)", f"re.match(r'{pat2.pattern}', w)"],
        n_range=[2**k for k in range(24)],
        xlabel='Length of list',
        equality_check=None
    )
fig.suptitle('re.match vs re.search')
fig.tight_layout();