Python技术迷

Python正则表达式中的match和search的区别

今天我们来聊一个面试中常见的Python正则表达式的陷阱:match和search的区别。这个问题每次面试时都会被拿出来问,大家都觉得好像差不多,可实际一用起来,才发现这两者有着微妙的差异。程序员嘛,生活就是要时刻警惕这些坑,不然不小心就栽进去了。

好了,不卖关子了,直接进入正题。我们先简单看一下它们各自的功能。

re.match 和 re.search 的基本区别

  1. re.match:

  • 只在字符串的开头进行匹配。如果匹配成功,它就返回一个匹配对象;如果开头不匹配,直接返回 None。
  • 说白了,match 就是个“固执的家伙”,它只认开头,不管后面的内容是啥。
  • re.search:

    • 在整个字符串中进行查找,找到第一个匹配的部分就返回匹配对象;如果没有匹配的内容,它也返回 None。
    • search 比 match 要“宽容”一些,不管你在什么地方找到匹配,它都能接纳。

    看个例子

    假如我们有一个正则表达式 r'\d+',用来匹配数字。现在我们有一个字符串 '123abc',想要看看这两个函数的行为。

    import re

    pattern = r'\d+'
    text = "123abc"

    # 使用 match
    match_result = re.match(pattern, text)
    if match_result:
        print("match found:", match_result.group())
    else:
        print("match not found")

    # 使用 search
    search_result = re.search(pattern, text)
    if search_result:
        print("search found:", search_result.group())
    else:
        print("search not found")

    输出:

    match not found
    search found: 123

    解释:

    • re.match 只在字符串开头匹配,如果开头是 123abc,它会尝试匹配数字,但是它需要的是从开头开始就符合正则表达式的模式,而这时它直接失败了。
    • re.search 就宽松多了,虽然字符串开头有 123,它还是能找到第一个匹配项,所以成功返回了 123。

    正则表达式在工作中的使用

    在实际工作中,我们经常需要用正则表达式来进行字符串匹配。比如我们有一个场景,需要判断一个手机号是否符合规定。

    代码示例:用 re.match 判断手机号

    假设我们规定手机号必须是以 1 开头,接下来是 10 位数字:

    import re

    def validate_phone_number(phone):
        pattern = r'^1\d{10}$'  # 以1开头,后面跟10个数字
        if re.match(pattern, phone):
            return "Valid phone number"
        else:
            return "Invalid phone number"

    # 测试
    phone = "13812345678"
    print(validate_phone_number(phone))  # Valid phone number

    解释:

    • 这里使用 ^ 来表示字符串的开头,$ 表示字符串的结尾,整个正则表达式就限定了手机号必须严格符合这个规则。
    • 如果是用 re.search,虽然也能找到手机号中的数字部分,但这不是我们想要的,因为我们需要确保整个字符串都是符合要求的。

    代码示例:用 re.search 查找文本中的手机号

    假设我们有一个长文本,要在其中查找手机号,我们就应该用 re.search 来做。

    import re

    def find_phone_numbers(text):
        pattern = r'\d{11}'  # 匹配11位数字
        matches = re.findall(pattern, text)
        return matches

    # 测试
    text = "我的电话是13812345678,另一个是13998765432,赶紧联系我!"
    print(find_phone_numbers(text))  # ['13812345678', '13998765432']

    解释:

    • 这里的正则表达式 \d{11} 就可以匹配文本中的任何11位数字,re.search 会遍历整个文本,找出所有符合条件的数字并返回。

    区别小结

    • re.match 主要用来检测字符串的开头是否符合规则。
    • re.search 则会扫描整个字符串,找到第一个符合规则的部分。

    在你写代码的时候,记得根据需求来选择。比如,你只关心字符串开头的匹配,match 就是你需要的工具;如果你关心的是字符串中任意位置的匹配,那就用 search 吧。

    什么时候用 re.match 或者 re.search

    好吧,说了这么多,大家肯定有点困惑了,什么时候选 match,什么时候用 search?别急,我来给你总结几点经验:

    1. **用 match**:

    • 当你只关心字符串的开头是否符合某种模式时,使用 match。
    • 比如验证一些格式要求严格的字段,或者检查某个特定条件是否出现在开头。
  • **用 search**:

    • 当你只想找出字符串中符合正则的某一部分时,使用 search。
    • 比如从一大段文本中找出某个信息,或者你只关心某个模式在哪里出现都可以。

    用正则表达式时要小心

    作为一个程序员,在用正则表达式的时候,千万要注意正则的贪婪性。正则默认是贪婪的,意味着它会尽可能多地匹配字符。有时你可能会遇到意料之外的匹配结果,导致代码出错。

    示例:贪婪匹配与非贪婪匹配

    import re

    text = "<div>First part</div><div>Second part</div>"

    # 贪婪匹配
    greedy_result = re.findall(r'<div>.*</div>', text)
    print("Greedy match:", greedy_result)

    # 非贪婪匹配
    non_greedy_result = re.findall(r'<div>.*?</div>', text)
    print("Non-greedy match:", non_greedy_result)

    输出:

    Greedy match: ['<div>First part</div><div>Second part</div>']
    Non-greedy match: ['<div>First part</div>', '<div>Second part</div>']

    解释:

    • 贪婪匹配 .* 会尽可能多地匹配字符,因此它匹配了整个字符串。
    • 非贪婪匹配 .*? 则会尽可能少地匹配字符,所以它分别匹配了两个 <div> 标签中的内容。

    总结

    通过这个例子,大家可以发现,re.match 和 re.search 虽然在某些方面看起来很像,但实际用途却大有不同。使用它们时,要清楚地了解自己到底需要检查的是整个字符串的开头,还是字符串中的任意位置。毕竟,正则这个工具,不灵活的用起来可是很容易出错的。

    对编程、职场感兴趣的同学,大家可以联系我微信:golang404,拉你进入“程序员交流群”。
    🔥虎哥私藏精品 热门推荐🔥

    虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》。

    资料包含了《IDEA视频教程》、《最全python面试题库》、《最全项目实战源码及视频》及《毕业设计系统源码》,总量高达650GB,全部免费领取。