User:Xyy23330121/Python/正则表达式

来自维基学院


正则表达式是处理、分割字符串的重要工具。它可以以一定的模式对字符串进行“匹配”,从而可以按模式筛选字符串或子字符串,并对筛选结果进行操作。

Python 专属的正则表达式语法[编辑 | 编辑源代码]

以下语法中,一部分为 Python 的正则表达式专属。在其它的正则表达式实现中使用可能会出错。

基本匹配[编辑 | 编辑源代码]

正则表达式中,大多数字符都只匹配其自身。比如:正则表达式中 t 会唯一的匹配字符 t,而正则表达式 e 会唯一的匹配字符 e等等。

正则表达式满足相加性质。即当“正则表达式A”匹配“字符串a”,而“正则表达式B”匹配“字符串b”时。拼接 A 和 B 得到的“正则表达式A+B”,一定匹配拼接得到的“字符串a+b”。

比如,正则表达式 test 会唯一的匹配字符串 test

元字符[编辑 | 编辑源代码]

对于正则表达式而言,上面的“基本匹配”是不足以满足“按模式匹配”的需要的。为了描述模式,正则表达式设置了以下的元字符:

. ^ $ * + ? { } [ ] \ | ( )

这些元字符在正则表达式中表示特殊的意思,从而也就不能匹配字符串中相同字符。元字符之外的字符,都只匹配其自身。

以下将讲解元字符的用法。

^ 字符串开头[编辑 | 编辑源代码]

匹配位于字符串开头的空字符串。比如:

  • 正则表达式 a 和字符串 aba 匹配,会得到两个子字符串 a
  • 而正则表达式 ^a 和字符串 aba 匹配,只会匹配到位于字符串开头的子字符串。

$ 字符串末尾[编辑 | 编辑源代码]

匹配字符串末尾的空字符串,如果字符串末尾是换行符,也可以匹配该换行符前的空字符串。

\ 转义字符[编辑 | 编辑源代码]

通过 \,我们可以在正则表达式转义出匹配元字符的表达式。比如:

  • \[ 唯一地匹配字符 [
  • \\ 唯一地匹配字符 \

创建正则表达式时,是通过字符串来创建的。如果要创建正则表达式 \\,需要使用字符串 "\\\\"r"\\"。为了简便和易于阅读,在创建正则表达式时,请务必使用“原始字符串”的方式。

字符串的转义[编辑 | 编辑源代码]

Python 字符串支持的、以下转义序列也被用作正则表达式的转义。

转义字符 含义
\a 响铃(BEL)
\b 退格(BS)
\f 换页(FF)
\n 换行(LF)
\r 回车(CR)
\t 横向制表符(TAB)
\v 纵向制表符(VT)
\ooo 八进制数ooo所表示的字符
\xhh 二位十六进制数hh所表示的字符
\N{name} Unicode 数据库中,名为name的字符,
name可以为别名。有些别名不被支持。
\uxxxx 四位十六进制数xxxx所表示的字符
\Uxxxxxxxx 八位十六进制数xxxxxxxx表示的字符

特别的,以下几种方式与字符串中的使用有区别:

  • 对于 \ooo,只有以下两种方式会被视为此转义:
    • 首位数字是 0,比如 \01
    • 使用了完整的三位数字,比如 \123
  • 对于 \b,只有在“字符类”中,才认为是退格符。
  • 对于 \uxxxx\Uxxxxxxxx\N{name},仅在 Unicode 字符串模式才会被识别。

其它转义[编辑 | 编辑源代码]

转义 解释
\A 只匹配字符串开头
\b 只匹配单词开头或结尾
单词开头和结尾被定义为:
  • \w\W 之间的空字符串
  • 或者 \w 和字符串开头或结尾之间的空字符串
\B 非 \b 的空字符串
\Z 只匹配字符串结尾

关于 \w\W,参见下面 ASCII 模式和 Unicode 模式 章节。

[...] 字符类[编辑 | 编辑源代码]

[] 括住的部分为字符类。字符类会匹配任何在类中的字符,比如:[aA1] 能匹配三个字符串:aA1

\以外的元字符在字符类中都不起作用。比如:[$] 会唯一的匹配字符 $

如果要添加 ] 到字符类中,则必须要使用转义方法 \]

除上述规则以外,为简便起见,字符类有以下的特殊的表示方式:

字符类:“-”[编辑 | 编辑源代码]

- 可以在字符类中表示“范围”,比如:

  • [a-c] 能匹配 abc
  • [a-zA-Z0-9] 能匹配任何单个英文字母字符。

需要注意的是,如果把 - 放在首尾,则不会表示“范围”,而是表示单独的 - 字符。比如:

  • [-a] 能匹配 -a
  • [-a-c] 能匹配 -abc

字符类:“^”[编辑 | 编辑源代码]

若字符类中第一个字符为 ^,则认为是对字符类取反,比如:

  • [^a] 能匹配任何不是 a 的字符。
  • [^a-z] 能匹配任何不是小写英文字母的字符。

需要注意的是,如果把 ^ 放在中间,则没有此效果,比如:

  • [ ^] 能匹配空格字符和 ^

. 任意字符[编辑 | 编辑源代码]

. 可以匹配除了换行符以外的任意字符。

重复匹配[编辑 | 编辑源代码]

通过以下的方式,可以设定匹配次数。

* 匹配任意次[编辑 | 编辑源代码]

正则表达式 ab* 会匹配字符串 aababb 等。

+ 匹配 >=1 次[编辑 | 编辑源代码]

正则表达式 ab+ 会匹配字符串 ababb 等。但不会匹配 a

? 匹配 0 或 1 次[编辑 | 编辑源代码]

正则表达式 ab? 会匹配字符串 a 和字符串 ab

{m} 匹配 m 次[编辑 | 编辑源代码]

比如:正则表达式 a{3} 会匹配字符串 aaa

使用 a{m} 时,m 必须是正整数。

{m,n} 匹配 m ~ n 次[编辑 | 编辑源代码]

m 和 n 必须是正整数。

比如:正则表达式 a{2,3} 会匹配字符串 aa 和字符串 aaa

特别的,使用 {,n} 会匹配 0 ~ n 次。使用 {m,} 会匹配 m ~ 任意次。使用 {,} 等同于使用 *

重复匹配算法[编辑 | 编辑源代码]

在进行重复匹配时,默认会先尽可能多地进行匹配。在正则表达式 ^[a-z]*reabrer进行匹配时,会进行以下步骤:

  • [a-z]* 匹配 abrer
    • r 到字符串末尾,无法匹配,回退
  • [a-z]* 匹配 abre
    • r 匹配 r
    • e 到字符串末尾,无法匹配,回退
  • [a-z]* 匹配 abr
    • r 无法匹配 e ,回退
  • [a-z]* 匹配 ab
    • r 匹配 r
    • e 匹配 e
    • 正则表达式结束,匹配完毕,匹配到子字符串 abre

可以看出 [a-z]* 会先尝试匹配 5 个字符、再尝试匹配 4 个字符,从匹配字符数从多到少进行尝试。这种尝试的模式被称为“贪婪模式”。

? 非贪婪模式[编辑 | 编辑源代码]

在代表重复匹配的结构后添加 ? ,则会改为匹配字符数从少到多进行尝试。

比如,在正则表达式 ^[a-z]*?reabrer进行匹配时,会进行以下步骤:

  • [a-z]*? 匹配 a
    • r 无法匹配 b ,回退
  • [a-z]*? 匹配 ab
    • r 匹配 r
    • e 匹配 e
    • 正则表达式结束,匹配完毕,匹配到子字符串 abre

+ 占有模式[编辑 | 编辑源代码]

在代表重复匹配的结构后添加 + ,则会在贪婪模式的基础上,不允许回退。这也被称为“占有模式”。

比如,在正则表达式 ^a?[a-z]*+reabrer进行匹配时,会进行以下步骤:

  • a? 匹配 a
    • [a-z]*+ 匹配 brer 并“占有”
      • r 无法匹配字符串末尾,回退
        不能回退并修改[a-z]*+的匹配结果
        回退并修改在[a-z]*+之前的a?
  • a? 匹配空字符串
    • [a-z]*+ 匹配 abrer 并“占有”
      • r 无法匹配字符串末尾,回退
        不能回退并修改[a-z]*+的匹配结果
  • 正则表达式结束,匹配完毕,没有匹配到字符串。

“占有模式”和“非贪婪模式”不能同时设置。

| 或[编辑 | 编辑源代码]

正则表达式 a|b 会匹配字符串 ab

特别的,如果左边的“分支”匹配成功了,就不会尝试对右边的分支进行匹配。比如:

[a-z]*|[0-9]*114 和字符串进行匹配时,会先匹配 [a-z]*114,匹配失败后再尝试匹配 [0-9]*114。如果 [a-z]*114 匹配成功,就不会尝试 [0-9]*114 了。举个例子:

  • [a-z]*|[0-9]*1141140114 匹配:
    • 尝试匹配 [a-z]*114
      • [a-z]* 匹配到空字符串
        • 114 匹配到 114
          匹配成功,匹配到 114

在匹配过程中,根本不会尝试匹配 [0-9]*114。即便 [0-9]*114 能匹配完整的 1140114

(...) 组合[编辑 | 编辑源代码]

我们可以把一系列正则表达式作成组合,并对组合进行操作。比如:

  • 正则表达式 (ab)? 会匹配字符串 ab 和字符串 abab
  • 正则表达式 (ab)|c 会匹配字符串 ab 和字符串 c
匹配方式字符
字符 匹配方式
i 忽略大小写
m 允许多行匹配
s . 会匹配任意字符
(包括换行符)
x 带注释的正则表达式
a ASCII 模式
u Unicode 模式
L 按本地语言区域模式

(?imsxauL) 设置匹配方式[编辑 | 编辑源代码]

以上的匹配方式并不绝对。如果在正则表达式中,出现了形如 (?a) 的组,则会按照该组的内容设置匹配方式。

这种类型的组不会匹配任何内容,它只匹配空字符串。

右表列出了该组中,可用的字符。这些字符可以进行组合,以同时设置多个匹配方式。

其中,ASCII 模式、 Unicode 模式和“按本地语言区域”模式互相矛盾,因此不能相互组合。在未设置这些模式时,默认使用 Unicode 模式。“按本地语言区域”的模式不可靠,不建议使用。

ASCII 模式和 Unicode 模式[编辑 | 编辑源代码]

ASCII 模式和 Unicode 模式设置以下转义得到的字符类的行为:

转义 ASCII 模式 Unicode 模式
\d [0-9] 任何属于 Unicode 字符类别 ND 的字符。
\D [^0-9] 任何非 \d 的字符。
\s [ \t\n\r\f\v] 任何 Unicode 空白字符
\S [^ \t\n\r\f\v] 任何非 Unicode 空白字符
\w [a-zA-Z0-9_] 任何 str.isalnum() 方法返回 True 的字符
以及下划线
\W [^a-zA-Z0-9_] 任何 str.isalnum() 方法返回 False 的字符
不包含下环线

多行匹配[编辑 | 编辑源代码]

多行匹配模式会影响 ^$ 的行为。

在设置了多行匹配模式后:

  • ^ 会匹配位于换行符后的空字符串。
  • $ 会匹配位于换行符前的空字符串。

带注释的正则表达式[编辑 | 编辑源代码]

此时,允许创建带有注释的、美观的正则表达式。以下两种方式得到的结果是相同的:

pattern = r"(0b[01]*)|(0o[0-7]*)|([0-9]*)|(0x[0-9a-fA-F]*)"
r = re.compile(pattern) #编译正则表达式
pattern = r"""(?x) #匹配数字:
  (0b[01]*)          #二进制数字
| (0o[0-7]*)         #八进制数字
| ([0-9]*)           #十进制数字
| (0x[0-9a-fA-F]*)   #十六进制数字
"""
r = re.compile(pattern) #编译正则表达式

此时,正则表达式会忽略字符串中的空格,以及多行字符串中、自动加入的换行符。

如果要匹配空格,则使用 \ 。如果要匹配换行符,则使用 \n

(?imsxauL-imsx:...) 设置局部匹配方式[编辑 | 编辑源代码]

仅对其中的正则表达式启用或弃用某匹配方式。比如:

  • (?i)ab 会匹配:abAbaBAB
  • (?i)a(?-i:b) 会匹配:abAb。弃用了对 b 的“忽略大小写模式”。
  • a(?i:b) 会匹配:aBAB。仅对 b 启用“忽略大小写模式”。

特别的,不允许简单地弃用“ASCII 模式”“Unicode 模式”和“按本地语言区域模式”。

(?>...) 占有模式[编辑 | 编辑源代码]

该组会对组中的表达式启用“占有模式”,比如:

  • x*+ 等同于 (?>x*)

(?:...) 非捕获模式[编辑 | 编辑源代码]

此方法会影响 Python 在进行匹配时、保存的结果。比如:

  • (xyz) 在匹配时,会在结果中保存匹配到的 xyz
  • (?:xy(z)) 在匹配时,会匹配到相同的内容,但结果中仅保存 z

(?P<name>...) 带命名的组[编辑 | 编辑源代码]

通过这种方式,可以给组进行命名。re.Match 实例的多个方法,以及 re.Pattern 实例的 sub 方法会引用命名组匹配到的内容。

被命名的组可以用以下方式,在正则表达式中引用。

(?P=name)[编辑 | 编辑源代码]

仅匹配第一次匹配到 (?P<name>...) 时、匹配到的内容。

import re
p = re.compile(r'''(?x)
<(?P<ele_name>[a-zA-Z]+).*?> #匹配<html>
.*                           #匹配中间
</(?P=ele_name)>             #匹配</html>
''')
s = '<p>Paragraph</pi>'
s1 = '<p>Paragraph</p>'

print(p.match(s).string[matchobj.start():matchobj.end()])  #输出空字符串,没有得到匹配。
print(p.match(s1).string[matchobj.start():matchobj.end()]) #输出:<p>Paragraph</p>

\num[编辑 | 编辑源代码]

类似 (?P=name) ,但此方式也可以用于引用一般的组。

仅匹配第一次匹配到第 num 个组时,匹配到的内容。

(?#...) 注释[编辑 | 编辑源代码]

作为注释使用,仅匹配空字符串。

(?=...) 前视断言[编辑 | 编辑源代码]

仅匹配空字符串。

其中的正则表达式和当前位置右侧的内容相匹配,则匹配空字符串成功。否则匹配失败。

比如:正则表达式 Isaac(?= Newton) 将会匹配 Isaac Newton 中的 Isaac,但不会匹配 Isaac Brown 中的 Isaac

这种方式被称为前视断言 (lookahead assertion)。

(?!...) 否定型前视断言[编辑 | 编辑源代码]

仅匹配空字符串。

其中的正则表达式和当前位置右侧的内容不匹配,则匹配空字符串成功。否则匹配失败。

比如:正则表达式 Isaac(?! Newton) 将会匹配 Isaac Brown 中的 Isaac,但不会匹配 Isaac Newton 中的 Isaac

这种方式被称为否定型前视断言 (negative lookahead assertion)。

(?<=...) 肯定型后视断言[编辑 | 编辑源代码]

仅匹配空字符串。

其中的正则表达式与当前位置左侧的内容相匹配,则匹配空字符串成功。否则匹配失败。

这种方式被称为肯定型后视断言 (positive lookbehind assertion)。

(?<!…) 否定型后视断言[编辑 | 编辑源代码]

仅匹配空字符串。

其中的正则表达式和当前位置左侧的内容不匹配,则匹配空字符串成功。否则匹配失败。

这种方式被称为否定型后视断言 (negative lookbehind assertion)。

(?(num/name)yes-pattern|no-pattern) 条件匹配[编辑 | 编辑源代码]

在匹配时,之前已有的、\num(?P=name) 所示的组、匹配的并非空字符串,则按照 yes-pattern 进行匹配。否则,按照 no-pattern 进行匹配。

Python 使用正则表达式[编辑 | 编辑源代码]

旗标列表
旗标 匹配方式
re.I
re.IGNORECASE
忽略大小写
re.M
re.MULTILINE
允许多行匹配
re.S
re.DOTALL
. 会匹配任意字符
(包括换行符)
re.X
re.VERBOSE
带注释的正则表达式
re.A
re.ASCII
ASCII 模式
re.U
re.UNICODE
Unicode 模式
re.L
re.LOCALE
按本地语言区域模式
re.NOFLAG 表示空旗标。
特别的:re.NOFLAG 就是整数 0
re.DEBUG 显示有关编译表达式的调试信息。

旗标[编辑 | 编辑源代码]

旗标和上述 设置匹配方式 章节的效果是相同的。右表列出了可用的旗标。

在使用旗标时,可以用“按位或”运算符 | 组合多个旗标,并把结果传入下面函数中的 flags 参数中。

特别的:re.NOFLAG 和任何其它旗标进行组合,都会返回其它旗标。

re.DEBUG 会在使用正则表达式时,返回编译的结果。

re.compile(pattern, flags=0)[编辑 | 编辑源代码]

编译正则表达式。返回一个 re.Pattern 实例。re 模块是通过该类型的实例方法来进行匹配操作的。

re.Pattern 的属性
属性 解释
flags 旗标。是 compile 函数获取的旗标以及正则表达式中用 (?imsxauL) 设置的匹配方式的组合。
groups 捕获到的模式串中组的数量。
groupindex 映射由 (?P<name>) 定义的、有命名的组,其命名:索引位置组成的的字典。
如果没有有命名的组,那字典就是空的。
pattern 编译对象的原始样式字符串。

re.Pattern 实例方法[编辑 | 编辑源代码]

简单匹配[编辑 | 编辑源代码]

search(string[, pos[, endpos]])[编辑 | 编辑源代码]

string[pos: endpos] 中,查找匹配正则表达式的第一个位置,并返回对应的 re.Match 实例。如果没有匹配的位置,则返回 None。

match(string[, pos[, endpos]])[编辑 | 编辑源代码]

类似 search 方法,但是从 string[pos: endpos] 的开头开始匹配:不在 string[pos: endpos] 最开头的、匹配的位置都不会被匹配到。

fullmatch(string[, pos[, endpos]])[编辑 | 编辑源代码]

如果 string[pos: endpos] 整个字符串都与正则表达式匹配,则返回相应的 re.Match 实例。

finditer(string[, pos[, endpos]])[编辑 | 编辑源代码]

string[pos: endpos] 中,查找匹配正则表达式的、所有非重复的位置。

每个位置,都会生成一个 re.Match 实例。该函数会返回生成的 re.Match 实例组成的迭代器。

findall(string[, pos[, endpos]])[编辑 | 编辑源代码]

类似 finditer 方法。但是输出不同。

如果正则表达式中不包含一般的组,则会输出匹配的子字符串组成的列表。而如果正则表达式中包含组,则只输出组中的内容。比如:

import re
p = re.compile(r"\b[tT]\w+\b")
s1 = "This is a test string."
print(p.findall(s1)) #输出:['This', 'test']

q = re.compile(r"\b(\w+)=([^ ]+)")
s2 = '<img src="./image.png" width=100 height=100 />'
print(q.findall(s2)) #输出:[('src', '"./image.png"'), ('width', '100'), ('height', '100')]

分割[编辑 | 编辑源代码]

split(string, maxsplit=0)[编辑 | 编辑源代码]

string 中所有匹配的子字符串为分割符,返回分割后的、子字符串的列表。

最多进行 maxsplit 次分割。

特别的:

  • 如果 string 的开头被匹配,则返回的列表会以空字符串开头。
  • 如果正则表达式中包含一般的组(而非(?:...)的组),则会在分割中保留组内匹配的内容。
import re
p = re.compile("(a)(b)")
q = re.compile("(?:a)(?:b)")

s = "ab"

print(p.split(s)) #输出:['c', 'a', 'b', 'c']
print(q.split(s)) #输出:['c', 'c']

可以看出,使用一般的组的 p 在进行分割时,输出的结果中包含了组中的内容。而使用非捕获模式的 q 则没有进行这样的操作。

替换[编辑 | 编辑源代码]

sub(repl, string, count=0)[编辑 | 编辑源代码]

repl 所示的模式替换 string 中、匹配的内容。最多替换 count 次。repl 可以是字符串或函数。

如果 repl 是字符串,则直接进行替换,比如:

import re
p = re.compile(r"\b(\w+)=([^ ]+)")
s = '<img src="./image.png" width=100 height=100 />'
r = 'REPLACE'

print(p.sub(r, s))  #输出:<img REPLACE REPLACE REPLACE />

特别的, repl 中包含的、字符串转义序列的原始序列都会被转义。并且一些特殊的转义也会被执行:

特殊转义
转义 注释
\g<num> 正则表达式中,第 num 个组匹配到的内容
\num 正则表达式中,第 num 个组匹配到的内容
由于和 \ooo 冲突,num 不能超过 100,且
开头不能为 0。
\g<name> 正则表达式中,名为 name 的组匹配到的内容
import re
p = re.compile(r"\b(?P<arg>\w+)=([^ ]+)")
s = '<img src="./image.png" />'
r = r'\g<1>\1\g<arg>'

print(p.sub(r, s))  #输出:<img srcsrcsrc />

如果 repl 是函数,则该函数应可以传入每次匹配时,对应的 re.Match 实例,并返回替换的结果。

import re
p = re.compile(r"\b(\w+)=([^ ]+)")
s = '<img src="./image.png" width=100 height=100 />'
def r(matchobj):
    print(matchobj.string[matchobj.start():matchobj.end()])
    return "REPLACE"

print(p.sub(r, s))

输出为:

src="./image.png"
width=100
height=100
<img REPLACE REPLACE REPLACE />
subn(repl, string, count=0)[编辑 | 编辑源代码]

类似 sub 方法,但返回一个元组: (替换后字符串, 替换次数)

单次使用[编辑 | 编辑源代码]

如果只匹配一次,也可以直接使用 re 模块的以下函数:

函数 等同于
re.search(pattern, string, flags=0) re.compile(pattern, flags).search(string)
re.match(pattern, string, flags=0) re.compile(pattern, flags).match(string)
re.fullmatch(pattern, string, flags=0) re.compile(pattern, flags).fullmatch(string)
re.split(pattern, string, maxsplit=0, flags=0) re.compile(pattern, flags).split(string, maxsplit)
re.findall(pattern, string, flags=0) re.compile(pattern, flags).findall(string)
re.finditer(pattern, string, flags=0) re.compile(pattern, flags).finditer(string)
re.sub(pattern, repl, string, count=0, flags=0) re.compile(pattern, flags).sub(repl, string, count)
re.subn(pattern, repl, string, count=0, flags=0) re.compile(pattern, flags).subn(repl, string, count)

re.Match 的实例方法与属性[编辑 | 编辑源代码]

替换字符串[编辑 | 编辑源代码]

expand(template)[编辑 | 编辑源代码]

替换字符串 template 的内容,使其被转义。并返回替换后的字符串。

除字符串的转义之外,\1\g<1> 等也会被转义。

匹配到的组[编辑 | 编辑源代码]

group([group1, ...])[编辑 | 编辑源代码]

返回指定的组所匹配的内容。

其参数可以为正整数,代表组的索引(以 1 开头)。也可以是字符串,代表组的名称。

如果只有一个参数,则会返回字符串。如果有多个参数,则会返回字符串组成的元组。

特别的:

  • 参数 0 对应的是匹配的完整子字符串。
  • 不输入任何参数时,等同于 self.group(0)
import re
p = re.compile(r"\b(?P<attr>\w+)=(?P<value>[^ ]+)")
s = '<img src="./image.png" width=100 height=100 />'
m = p.search(s)

print(m.group())               #输出:src="./image.png"
print(m.group(0))              #输出:src="./image.png"
print(m.group(1))              #输出:src
print(m.group(1,2))            #输出:('src', '"./image.png"')
print(m.group("attr","value")) #输出:('src', '"./image.png"')
__getitem__(g)[编辑 | 编辑源代码]

使用 self[g] 来调用此方法。

等同于 self.group(g)

groups(default=None)[编辑 | 编辑源代码]

返回包含所有匹配子组的字符串。对于总共有 n 个组的情况,等同于 self.group(1,2,...,n)

形如 (pattern)* 的组可能一次都不会被匹配。此时,该组对应的位置会输出 default 的内容。

groupdict(default=None)[编辑 | 编辑源代码]

类似 groups 方法,但是返回的是 组的名称:匹配到的内容 的字典。

lastindex[编辑 | 编辑源代码]

该属性保存最后一个匹配的整数索引值。如果没有匹配的组,该属性为 None。

嵌套中的组不会被计数。比如,对于字符串 'ab',表达式 (a)b, ((a)(b)), 和 ((ab)) 将得到 lastindex == 1 , 而 (a)(b) 会得到 lastindex == 2 。

lastgroup[编辑 | 编辑源代码]

最后一个匹配的命名组名字。如果没有匹配的组,该属性为 None。

索引[编辑 | 编辑源代码]

start([group])[编辑 | 编辑源代码]

返回 group 所示的组,在原始字符串中起始位置的索引。

如果不输入 groupgroup 为 0,则返回匹配开始的位置。

end([group])[编辑 | 编辑源代码]

返回 group 所示的组,在原始字符串中结束位置的索引。

如果不输入 groupgroup 为 0,则返回匹配结束的位置。

span([group])[编辑 | 编辑源代码]

返回 (start([group]), end([group])) 元组。

匹配参数[编辑 | 编辑源代码]

生成 re.Match 需要用到 使用 re.compile(pattern).match(string, pos, endpos) 或 re.compile(pattern).search(string, pos, endpos) 等方法。以下属性表示其中的参数或对象。

pos[编辑 | 编辑源代码]

生成此 re.Match 实例所使用的参数 pos。

endpos[编辑 | 编辑源代码]

生成此 re.Match 实例所使用的参数 endpos。

re[编辑 | 编辑源代码]

生成此 re.Match 实例所使用的 re.Pattern 实例。

string[编辑 | 编辑源代码]

生成此 re.Match 实例所使用的参数 string。即被匹配的字符串。

其它操作[编辑 | 编辑源代码]

re.escape(pattern)[编辑 | 编辑源代码]

生成一个能匹配 pattern 字符串的、正则表达式字符串。

re.purge()[编辑 | 编辑源代码]

清除正则表达式的缓存。

注意事项[编辑 | 编辑源代码]

由于“多次匹配”的匹配机制,一些正则表达式可能会导致匹配时间随字符串长度指数增长,比如以下是导致 Cloudflare 在 2019 年 7 月发生全球宕机事故的正则表达式的一部分:

  • .*(?:.*=.*)

如果用这个正则表达式来匹配形如 title=User:Xyy23330121 的内容,它会:

  • .* 匹配到 title=User:Xyy23330121
    • .* 匹配到空字符串
      • = 到字符串尾,无法匹配,回退
    • 空字符串无法回退,继续向前回退。
  • .* 匹配到 title=User:Xyy2333012
    • .* 匹配到 1
      • = 到字符串尾,无法匹配,回退
    • .* 匹配到空字符串
      • = 匹配到 1,无法匹配,回退
    • 空字符串无法回退,继续向前回退。
  • .* 匹配到 title=User:Xyy233301
  • ...

从结论而言,它会尝试匹配总共 1 + 2 + ... + 16 = 136 次才会正确匹配所有内容。而如果等号后面的内容更多,情况只会更糟。

请在设置正则表达式时尽可能慎重。

參考文獻[编辑 | 编辑源代码]