📜  Python中的模式匹配与正则表达式

📅  最后修改于: 2022-05-13 01:54:46.307000             🧑  作者: Mango

Python中的模式匹配与正则表达式

先决条件: Python中的正则表达式

您可能熟悉通过按 ctrl-F 并输入您要查找的单词来搜索文本。正则表达式更进一步:它们允许您指定要搜索的文本模式。
正则表达式,简称正则表达式,是对文本模式的描述。例如,正则表达式中的 \d 代表数字字符,即 0 到 9 之间的任何单个数字。

  • 以下正则表达式在Python中用于匹配由三个数字、一个连字符、另外三个数字、另一个连字符和四个数字组成的字符串。
    Any other string would not match the pattern.
    \d\d\d-\d\d\d-\d\d\d\d
  • 正则表达式可以更加复杂。例如,在模式后的大括号 ({3}) 中添加 3 就像在说“匹配此模式三遍”。所以稍微短一点的正则表达式
    \d{3}-\d{3}-\d{4}

    (它匹配正确的电话号码格式。)

创建正则表达式对象

Python中的所有正则表达式函数都在 re 模块中

import re

要创建与电话号码模式匹配的 Regex 对象,请在交互式 shell 中输入以下内容。

phoneNumRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')

现在 phoneNumRegex 变量包含一个 Regex 对象。

匹配正则表达式对象

Regex 对象的 search() 方法搜索传递给该正则表达式的任何匹配字符串。 Match 对象有一个 group() 方法,该方法将从搜索的字符串中返回实际匹配的文本。

# Python program to illustrate
# Matching regex objects
import re
phoneNumRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
mo = phoneNumRegex.search('My number is 415-555-4242.')
print('Phone number found: ' + mo.group())

输出:

Phone number found: 415-555-4242

正则表达式匹配步骤

虽然在Python中使用正则表达式有几个步骤,但每个步骤都相当简单。

  1. 使用 import re 导入正则表达式模块。
  2. 使用 re.compile()函数创建一个 Regex 对象。 (记得使用原始字符串。)
  3. 将要搜索的字符串传递给 Regex 对象的 search() 方法。这将返回一个匹配对象。
  4. 调用 Match 对象的 group() 方法以返回实际匹配文本的字符串。

    用括号分组

    1. 匹配对象:假设您想将区号与电话号码的其余部分分开。添加括号将在正则表达式中创建组:(\d\d\d)-(\d\d\d-\d\d\d\d)。然后,您可以使用 group() 匹配对象方法从一组中获取匹配的文本。
      # Python program to illustrate
      # Matching regex objects
      # with grouping 
      import re
      phoneNumRegex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')
      mo = phoneNumRegex.search('My number is 415-555-4242.')
      print(mo.group(1))
      

      输出:

      '415'
      
    2. 一次检索所有组:如果您想一次检索所有组,请使用 groups() 方法——注意名称的复数形式。
      # Python program to illustrate
      # Matching regex objects
      # with groups 
      import re
      phoneNumRegex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')
      mo = phoneNumRegex.search('My number is 415-555-4242.')
      print(mo.groups())
      

      输出:

      ('415', '555-4242')
    3. 使用 mo.groups : mo.groups() 将返回一个包含多个值的元组,您可以使用多重赋值技巧将每个值分配给一个单独的变量,如下面的 areaCode, mainNumber = mo.groups() 行所示。
      # Python program to illustrate
      # Matching regex objects
      # with mo.groups() 
      import re
      phoneNumRegex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')
      mo = phoneNumRegex.search('My number is 415-555-4242.')
      areaCode, mainNumber = mo.groups()
      print(mainNumber)
      

      输出:

      '555-4242'
    4. 匹配括号:括号在正则表达式中具有特殊含义,但是如果您需要匹配文本中的括号,该怎么办。例如,您尝试匹配的电话号码可能在括号中设置了区号。在这种情况下,您需要使用反斜杠转义 ( 和 )字符。在交互式 shell 中输入以下内容:
      # Python program to illustrate
      # Matching regex objects
      # with grouping 
      import re
      phoneNumRegex = re.compile(r'(\(\d\d\d\)) (\d\d\d-\d\d\d\d)')
      mo = phoneNumRegex.search('My phone number is (415) 555-4242.')
      print(mo.group(1))
      

      输出:

      '(415)'

      传递给 re.compile() 的原始字符串中的 \( 和 \) 转义字符将匹配实际的括号字符。

    将多个组与管道匹配

    该|字符称为管道。您可以在任何想要匹配多个表达式之一的地方使用它。例如,正则表达式 r'Batman|Tina Fey' 将匹配 'Batman' 或 'Tina Fey'。

    当搜索到的字符串中同时出现 Batman 和 Tina Fey 时,第一次出现的匹配文本将作为 Match 对象返回。在交互式 shell 中输入以下内容:

    # Python program to illustrate
    # Matching regex objects
    # with multiple Groups with the Pipe
    import re
    heroRegex = re.compile (r'Batman|Tina Fey')
    mo1 = heroRegex.search('Batman and Tina Fey.')
    print(mo1.group())
    

    输出:

    'Batman'

    用大括号匹配特定的重复

    如果您有一个想要重复特定次数的组,请在您的正则表达式中使用大括号中的数字跟随该组。例如,正则表达式 (Ha){3} 将匹配字符串'HaHaHa',但不会匹配 'HaHa',因为后者只有 (Ha) 组的两次重复。

    您可以通过在大括号之间写入最小值、逗号和最大值来指定范围,而不是一个数字。例如,正则表达式 (Ha){3, 5} 将匹配 'HaHaHa'、'HaHaHaHa' 和 'HaHaHaHaHa'。

    您还可以省略大括号中的第一个或第二个数字,以使最小值或最大值不受限制。例如,(Ha){3, } 将匹配 (Ha) 组的三个或更多实例,而 (Ha){, 5} 将匹配零到五个实例。花括号可以帮助使您的正则表达式更短。这两个正则表达式匹配相同的模式:

    (Ha){3}
    (Ha)(Ha)(Ha)

    这两个正则表达式也匹配相同的模式:

    (Ha){3, 5}
    ((Ha)(Ha)(Ha))|((Ha)(Ha)(Ha)(Ha))|((Ha)(Ha)(Ha)(Ha)(Ha))

    在交互式 shell 中输入以下内容:

    # Python program to illustrate
    # Matching Specific Repetitions 
    # with Curly Brackets
    import re
    haRegex = re.compile(r'(Ha){3}')
    mo1 = haRegex.search('HaHaHa')
    print(mo1.group())
    

    输出:

    'HaHaHa'
    # Python program to illustrate
    # Matching Specific Repetitions 
    # with Curly Brackets
    import re
    haRegex = re.compile(r'(Ha){3}')
    mo2 = haRegex.search('Ha')== None
    print(mo2)
    

    输出:

    True
    

    在这里,(Ha){3} 匹配 'HaHaHa' 但不匹配 'Ha'。由于它不匹配 'Ha',因此 search() 返回 None。

    与问号的可选匹配

    有时,您只想选择匹配一种模式。也就是说,无论该位文本是否存在,正则表达式都应该找到匹配项。 ?字符将其前面的组标记为模式的可选部分。例如,在交互式 shell 中输入以下内容:

    # Python program to illustrate
    # optional matching
    # with question mark(?)
    import re
    batRegex = re.compile(r'Bat(wo)?man')
    mo1 = batRegex.search('The Adventures of Batman')
    print(mo1.group())
    

    输出:

    'Batman'
    # Python program to illustrate
    # optional matching
    # with question mark(?)
    import re
    batRegex = re.compile(r'Bat(wo)?man')
    mo2 = batRegex.search('The Adventures of Batwoman')
    print(mo2.group())
    

    输出:

    'Batwoman'

    禾)?正则表达式的一部分意味着模式 wo 是一个可选组。正则表达式将匹配其中包含零个实例或一个 wo 实例的文本。这就是为什么正则表达式同时匹配“蝙蝠女侠”和“蝙蝠侠”的原因。
    你能想到吗?就像说, “匹配这个问号之前的组中的零个或一个。”
    如果您需要匹配实际的问号字符,请使用 \? 对其进行转义。

    匹配零个或多个与星

    *(称为星号或星号)表示“匹配零个或多个”——星号之前的组可以在文本中出现任意次数。它可以完全不存在或一遍又一遍地重复。让我们再看看蝙蝠侠的例子。

    # Python program to illustrate
    # matching a regular expression
    # with asterisk(*)
    import re
    batRegex = re.compile(r'Bat(wo)*man')
    mo1 = batRegex.search('The Adventures of Batman')
    print(mo1.group())
    

    输出:

    'Batman'
    #python program to illustrate
    #matching a regular expression
    #with asterisk(*)
    import re
    batRegex = re.compile(r'Bat(wo)*man')
    mo2 = batRegex.search('The Adventures of Batwoman')
    print(mo2.group())
    

    输出:

    'Batwoman'
    # Python program to illustrate
    # matching a regular expression
    # with asterisk(*)
    import re
    batRegex = re.compile(r'Bat(wo)*man')
    mo3 = batRegex.search('The Adventures of Batwowowowoman')
    print(mo3.group())
    

    输出:

    'Batwowowowoman'

    对于“蝙蝠侠”,正则表达式的 (wo)* 部分匹配字符串中 wo 的零个实例;对于“蝙蝠女侠”, (wo)* 匹配 wo 的一个实例;对于“Batwowowowoman”,(wo)* 匹配 wo 的四个实例。

    如果您需要匹配实际的星号,请在正则表达式字符的星号前加上反斜杠 \*。

    与 Plus 匹配一个或多个

    * 表示“匹配零个或多个”,而 +(或加号)表示“匹配一个或多个”。与不要求其组出现在匹配字符串中的星号不同,加号之前的组必须至少出现一次。这不是可选的。在交互式 shell 中输入以下内容,并将其与上一节中的星型正则表达式进行比较:

    # Python program to illustrate
    # matching a regular expression
    # with plus(+)
    import re
    batRegex = re.compile(r'Bat(wo)+man')
    mo1 = batRegex.search('The Adventures of Batwoman')
    print(mo1.group())
    

    输出:

    'Batwoman'
    # Python program to illustrate
    # matching a regular expression
    # with plus(+)
    import re
    batRegex = re.compile(r'Bat(wo)+man')
    mo2 = batRegex.search('The Adventures of Batwowowowoman')
    print(mo2.group())
    

    输出:

    'Batwowowowoman'

    batRegex = re.compile(r'Bat(wo)+man')

    # Python program to illustrate
    # matching a regular expression
    # with plus(+)
    import re
    batRegex = re.compile(r'Bat(wo)+man')
    mo3 = batRegex.search('The Adventures of Batman')== None
    print(mo3)
    

    输出:

    True

    正则表达式 Bat(wo)+man 将不匹配字符串“蝙蝠侠历险记”,因为加号至少需要一个 wo。

    如果您需要匹配实际的加号字符,请在加号前加上反斜杠以将其转义:\+。