跳转到内容

Python 编程/正则表达式

来自维基教科书,开放世界中的开放书籍


Python 包含一个用于在字符串上使用正则表达式的模块。有关编写正则表达式和不特定于 Python 的语法的更多信息,请参阅正则表达式维基教科书。Python 的正则表达式语法类似于Perl 的

要开始在您的 Python 脚本中使用正则表达式,请导入“re”模块

import re

Python 中的正则表达式函数一览

import re
if re.search("l+","Hello"):        print(1) # Substring match suffices
if not re.match("ell.","Hello"):   print(2) # The beginning of the string has to match
if re.match(".el","Hello"):        print(3)
if re.match("he..o","Hello",re.I): print(4) # Case-insensitive match
print(re.sub("l+", "l", "Hello"))           # Prints "Helo"; replacement AKA substitution
print(re.sub(r"(.*)\1", r"\1", "HeyHey"))   # Prints "Hey"; backreference
print(re.sub("EY", "ey", "HEy", flags=re.I))# Prints "Hey"; case-insensitive sub
print(re.sub(r"(?i)EY", r"ey", "HEy"))      # Prints "Hey"; case-insensitive sub
for match in re.findall("l+.", "Hello Dolly"):
  print(match)                              # Prints "llo" and then "lly"
for match in re.findall("e(l+.)", "Hello Dolly"):
  print(match)                              # Prints "llo"; match picks group 1
for match in re.findall("(l+)(.)", "Hello Dolly"):
  print(match[0], match[1])                 # The groups end up as items in a tuple
match = re.match("(Hello|Hi) (Tom|Thom)","Hello Tom Bombadil")
if match:                                 # Equivalent to if match is not None
  print(match.group(0))                   # Prints the whole match disregarding groups
  print(match.group(1) + match.group(2))  # Prints "HelloTom"

匹配和搜索

[编辑 | 编辑源代码]

正则表达式的最常见用途之一是提取字符串的一部分或测试字符串中是否存在模式。Python 提供了几个函数来执行此操作。

match 和 search 函数的功能基本相同,不同的是,match 函数只有在模式匹配要搜索的字符串的开头时才会返回结果,而 search 会在字符串中的任何位置找到匹配项。

>>> import re
>>> foo = re.compile(r'foo(.{,5})bar', re.I+re.S)
>>> st1 = 'Foo, Bar, Baz'
>>> st2 = '2. foo is bar'
>>> search1 = foo.search(st1)
>>> search2 = foo.search(st2)
>>> match1 = foo.match(st1)
>>> match2 = foo.match(st2)

在此示例中,match2 将为None,因为字符串st2 不以给定模式开头。其他 3 个结果将是 Match 对象(见下文)。

您也可以在不编译正则表达式的情况下进行匹配和搜索

>>> search3 = re.search('oo.*ba', st1, re.I)

这里我们使用 re 模块的 search 函数,而不是模式对象的 search 函数。在大多数情况下,最好先编译表达式。并非所有 re 模块函数都支持 flags 参数,如果表达式使用不止一次,则先编译更高效,并导致代码更简洁。

编译后的模式对象函数也有参数用于开始和结束搜索,以在给定字符串的子字符串中搜索。在本节的第一个示例中,match2 没有返回结果,因为模式不在字符串的开头,但如果我们这样做

>>> match3 = foo.match(st2, 3)

它可以工作,因为我们告诉它从字符串中的第 3 个字符开始搜索。

如果我们要搜索模式的多个实例怎么办?然后我们有两个选择。我们可以在循环中使用 search 和 match 函数的 start 和 end 位置参数,从上一个匹配对象(见下文)获取要开始的位置,或者我们可以使用 findall 和 finditer 函数。findall 函数返回一个匹配字符串的列表,对于简单的搜索非常有用。对于任何稍微复杂的东西,都应该使用 finditer 函数。它返回一个迭代器对象,在循环中使用时,会生成 Match 对象。例如

>>> str3 = 'foo, Bar Foo. BAR FoO: bar'
>>> foo.findall(str3)
[', ', '. ', ': ']
>>> for match in foo.finditer(str3):
...     match.group(1)
...
', '
'. '
': '

如果您要迭代搜索结果,使用 finditer 函数几乎总是更好的选择。

匹配对象

[编辑 | 编辑源代码]

Match 对象由 search 和 match 函数返回,并包含有关模式匹配的信息。

group 函数返回对应于表达式捕获组(表达式中用()括起来的部分)的字符串,或者如果未给出组号,则返回整个匹配项。使用上面定义的search1 变量

>>> search1.group()
'Foo, Bar'
>>> search1.group(1)
', '

捕获组也可以使用特殊语法赋予字符串名称,并通过matchobj.group('name')引用。对于简单的表达式,这是不必要的,但是对于更复杂的表达式,它非常有用。

您还可以使用 start 和 end 函数获取匹配项或组在字符串中的位置

>>> search1.start()
0
>>> search1.end()
8
>>> search1.start(1)
3
>>> search1.end(1)
5

这将分别返回整个匹配项的开始和结束位置以及第一个(在本例中也是唯一一个)捕获组的开始和结束位置。

正则表达式的另一个用途是替换字符串中的文本。要在 Python 中执行此操作,请使用 sub 函数。

sub 最多接受 3 个参数:要替换成的文本、要替换的文本以及可选的要执行的最大替换次数。与匹配和搜索函数不同,sub 返回一个字符串,它包含所给定的文本,其中进行了替换。

>>> import re
>>> mystring = 'This string has a q in it'
>>> pattern = re.compile(r'(a[n]? )(\w) ')
>>> newstring = pattern.sub(r"\1'\2' ", mystring)
>>> newstring
"This string has a 'q' in it"

这会将任何以“a”或“an”开头的单个字母数字字符(在正则表达式语法中为 \w)括在单引号中。替换字符串中的\1\2 是对表达式中 2 个捕获组的反向引用;这些将是 Match 对象中 group(1) 和 group(2) 的搜索结果。

subn 函数与 sub 类似,不同的是它返回一个元组,包含结果字符串和执行的替换次数。使用之前的字符串和表达式

>>> subresult = pattern.subn(r"\1'\2' ", mystring)
>>> subresult
("This string has a 'q' in it", 1)

在不构建和编译模式对象的情况下进行替换

>>> result = re.sub(r"b.*d","z","abccde")
>>> result
'aze'

split 函数根据给定的正则表达式拆分字符串

>>> import re
>>> mystring = '1. First part 2. Second part 3. Third part'
>>> re.split(r'\d\.', mystring)
['', ' First part ', ' Second part ', ' Third part']

escape 函数会转义字符串中的所有非字母数字字符。如果需要获取可能包含正则表达式元字符(如(.)的未知字符串并从中创建正则表达式,这将很有用。

>>> re.escape(r'This text (and this) must be escaped with a "\" to use in a regexp.')
'This\\ text\\ \\(and\\ this\\)\\ must\\ be\\ escaped\\ with\\ a\\ \\"\\\\\\"\\ to\\ use\\ in\\ a\\ regexp\\.'

正则表达式中使用的不同标志

缩写 完整名称 描述
re.I re.IGNORECASE 使正则表达式不区分大小写
re.L re.LOCALE 使某些特殊序列(\w, \W, \b, \B, \s, \S)的行为取决于当前区域设置
re.M re.MULTILINE 使^$ 字符在每行的开头和结尾处匹配,而不仅仅是在字符串的开头和结尾处匹配
re.S re.DOTALL 使. 字符匹配包括换行符在内的每个字符。
re.U re.UNICODE 使\w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性
re.X re.VERBOSE 忽略空格,除非它在字符类中或前面带有未转义的反斜杠,并忽略#(除非它在字符类中或前面带有未转义的反斜杠)以及后面的所有内容到行尾,因此它可以被用作注释。这允许使用更简洁的正则表达式。

模式对象

[编辑 | 编辑源代码]

如果您要在一个程序中多次使用相同的正则表达式,或者您只是想以某种方式将正则表达式分开,您应该创建一个模式对象,并在以后搜索/替换时引用它。

要创建模式对象,请使用 compile 函数。

import re
foo = re.compile(r'foo(.{,5})bar', re.I+re.S)

第一个参数是模式,它匹配字符串“foo”,后面跟着最多 5 个任意字符,然后是字符串“bar”,将中间字符存储到一个组中,这将在后面讨论。第二个可选参数是修改正则表达式行为的标志或标志集。标志本身只是引用正则表达式引擎使用的整数的变量。在其他语言中,这些将是常量,但 Python 没有常量。一些正则表达式函数不支持在函数中直接定义模式时添加标志作为参数,如果您需要任何标志,最好使用编译函数来创建模式对象。

表达式字符串前面的 r 表示它应该被视为原始字符串。在编写正则表达式时,通常应该使用它,这样反斜杠就会被逐字解释,而不是必须转义。

[编辑 | 编辑源代码]
华夏公益教科书