7.2. re — 正则表达式操作 — Python 文档
7.2. 关于 — 正则表达式操作
该模块提供类似于 Perl 中的正则表达式匹配操作。 要搜索的模式和字符串都可以是 Unicode 字符串,也可以是 8 位字符串。
正则表达式使用反斜杠字符 ('\'
) 来指示特殊形式或允许使用特殊字符而不调用其特殊含义。 这与 Python 在字符串文字中出于相同目的使用相同字符的做法相冲突; 例如,要匹配文字反斜杠,可能必须将 '\\\\'
写为模式字符串,因为正则表达式必须为 \\
,并且每个反斜杠必须表示为 \\
] 在常规 Python 字符串文字中。
解决方案是对正则表达式模式使用 Python 的原始字符串表示法; 在以 'r'
为前缀的字符串文字中,不会以任何特殊方式处理反斜杠。 所以 r"\n"
是包含 '\'
和 'n'
的两字符字符串,而 "\n"
是包含换行符的单字符字符串。 通常模式将使用这种原始字符串表示法在 Python 代码中表示。
需要注意的是,大多数正则表达式操作都可以作为模块级函数和 RegexObject 方法使用。 这些函数是不需要您首先编译正则表达式对象的快捷方式,但会遗漏一些微调参数。
7.2.1. 正则表达式语法
正则表达式(或 RE)指定一组与之匹配的字符串; 此模块中的函数可让您检查特定字符串是否与给定正则表达式匹配(或者给定正则表达式是否与特定字符串匹配,归结为同一件事)。
正则表达式可以连接起来形成新的正则表达式; 如果A和B都是正则表达式,那么AB也是一个正则表达式。 一般来说,如果一个字符串 p 匹配 A 并且另一个字符串 q 匹配 B,那么字符串 pq 将匹配AB。 除非 A 或 B 包含低优先级操作,否则这适用; A和B之间的边界条件; 或有编号的组参考。 因此,复杂的表达式可以很容易地从更简单的原始表达式构造出来,比如这里描述的那些。 有关正则表达式的理论和实现的详细信息,请参阅上面引用的 Friedl 书,或几乎所有有关编译器构造的教科书。
下面简要说明正则表达式的格式。 如需更多信息和更温和的介绍,请参阅 正则表达式 HOWTO。
正则表达式可以包含特殊字符和普通字符。 大多数普通字符,如 'A'
、'a'
或 '0'
,都是最简单的正则表达式; 他们只是匹配自己。 您可以连接普通字符,因此 last
匹配字符串 'last'
。 (在本节的其余部分,我们将在 this special style
中编写 RE,通常不带引号,以及要匹配的字符串 'in single quotes'
。)
某些字符,例如 '|'
或 '('
,是特殊的。 特殊字符要么代表普通字符的类别,要么影响它们周围的正则表达式的解释方式。 正则表达式模式字符串可能不包含空字节,但可以使用 \number
表示法指定空字节,例如 '\x00'
。
重复限定符(*
、+
、?
、{m,n}
等)不能直接嵌套。 这避免了与非贪婪修饰符后缀 ?
以及其他实现中的其他修饰符的歧义。 要将第二次重复应用于内部重复,可以使用括号。 例如,表达式 (?:a{6})*
匹配六个 'a'
字符的任意倍数。
特殊字符是:
'.'
(点。)在默认模式下,这匹配除换行符之外的任何字符。 如果指定了 DOTALL 标志,则它匹配包括换行符在内的任何字符。
'^'
(Caret.) 匹配字符串的开头,在 MULTILINE 模式下也匹配紧接在每个换行符之后。
'$'
匹配字符串的结尾或字符串末尾的换行符之前,并且在 MULTILINE 模式下也匹配换行符之前。
foo
匹配 'foo' 和 'foobar',而正则表达式foo$
只匹配 'foo'。 更有趣的是,在'foo1\nfoo2\n'
中搜索foo.$
正常匹配 'foo2',但在 MULTILINE 模式下搜索 'foo1'; 在'foo\n'
中搜索单个$
将找到两个(空)匹配项:一个在换行符之前,一个在字符串的末尾。'*'
使生成的 RE 匹配前面 RE 的 0 次或多次重复,尽可能多的重复。
ab*
将匹配“a”、“ab”或“a”后跟任意数量的“b”。'+'
导致生成的 RE 匹配前面 RE 的 1 次或多次重复。
ab+
将匹配“a”后跟任何非零数量的“b”; 它不会只匹配“a”。'?'
导致生成的 RE 匹配前面 RE 的 0 或 1 次重复。
ab?
将匹配“a”或“ab”。*?
、+?
、??
'*'
、'+'
和'?'
限定符都是贪婪; 它们匹配尽可能多的文本。 有时这种行为是不受欢迎的; 如果 RE<.*>
与<a> b <c>
匹配,它将匹配整个字符串,而不仅仅是<a>
。 在限定符后添加?
使其以 non-greedy 或 minimal 方式执行匹配; 因为 将匹配尽可能少的 个字符。 使用 RE<.*?>
只会匹配<a>
。{m}
指定应该匹配前一个 RE 的 m 个副本; 较少的匹配会导致整个 RE 不匹配。 例如,
a{6}
将正好匹配六个'a'
字符,但不会匹配五个。{m,n}
使生成的 RE 匹配从 m 到 n 个重复前面的 RE,尝试匹配尽可能多的重复。 例如,
a{3,5}
将匹配 3 到 5 个'a'
字符。 省略 m 指定零的下限,省略 n 指定无限的上限。 例如,a{4,}b
将匹配aaaab
或一千个'a'
字符后跟一个b
,但不匹配aaab
。 逗号不能省略,否则修饰符会与前面描述的形式混淆。{m,n}?
使生成的 RE 匹配从 m 到 n 个重复前面的 RE,尝试匹配尽可能少的 次 重复。 这是前一个限定符的非贪婪版本。 例如,在 6 个字符的字符串
'aaaaaa'
上,a{3,5}
将匹配 5 个'a'
字符,而a{3,5}?
仅匹配 3 个字符。'\'
Either escapes special characters (permitting you to match characters like
'*'
,'?'
, and so forth), or signals a special sequence; special sequences are discussed below.如果您不使用原始字符串来表达模式,请记住 Python 还使用反斜杠作为字符串文字中的转义序列; 如果 Python 的解析器无法识别转义序列,则反斜杠和后续字符将包含在结果字符串中。 但是,如果 Python 能够识别结果序列,则反斜杠应重复两次。 这很复杂且难以理解,因此强烈建议您对除最简单的表达式之外的所有表达式都使用原始字符串。
[]
用于表示一组字符。 在一组中:
字符可以单独列出,例如
[amk]
将匹配'a'
、'm'
或'k'
。字符范围可以通过给出两个字符并用
'-'
分隔来表示,例如[a-z]
将匹配任何小写 ASCII 字母,[0-5][0-9]
将匹配所有两位数从00
到59
和[0-9A-Fa-f]
的数字将匹配任何十六进制数字。 如果-
被转义(例如[a\-z]
) 或者如果它作为第一个或最后一个字符放置(例如[a-]
),它将匹配文字'-'
。特殊字符在集合内失去其特殊含义。 例如,
[(+*)]
将匹配任何文字字符'('
、'+'
、'*'
或')'
。字符类,例如
\w
或\S
(定义如下)也可以在集合中使用,尽管它们匹配的字符取决于是 LOCALE 还是 UNICODE ] 模式生效。不在范围内的字符可以通过 补充 集合来匹配。 如果集合的第一个字符是
'^'
,则集合中所有 不是 的字符都将被匹配。 例如,[^5]
将匹配除'5'
之外的任何字符,而[^^]
将匹配除'^'
之外的任何字符。^
如果不是集合中的第一个字符,则没有特殊含义。要匹配集合内的文字
']'
,请在其前面加上反斜杠,或将其放在集合的开头。 例如,[()[\]{}]
和[]()[{}]
都将匹配一个括号。
'|'
A|B
,其中 A 和 B 可以是任意 RE,创建一个匹配 A 或 B 的正则表达式。'|'
可以通过这种方式分隔任意数量的 RE。 这也可以在组内使用(见下文)。 在扫描目标字符串时,从左到右尝试由'|'
分隔的 RE。 当一个模式完全匹配时,该分支被接受。 这意味着一旦A
匹配,B
将不会被进一步测试,即使它会产生更长的整体匹配。 换句话说,'|'
运算符从不贪婪。 要匹配文字'|'
,请使用\|
,或将其包含在字符类中,如[|]
。(...)
匹配括号内的任何正则表达式,并指示组的开始和结束; 执行匹配后可以检索组的内容,并且可以稍后在字符串中使用
\number
特殊序列进行匹配,如下所述。 要匹配文字'('
或')'
,请使用\(
或\)
,或将它们包含在字符类中:[(] [)]
。(?...)
这是一个扩展符号(
'('
后面的'?'
没有其他意义)。'?'
之后的第一个字符决定了构造的含义和进一步的语法是什么。 扩展通常不会创建新组;(?P<name>...)
是此规则的唯一例外。 以下是当前支持的扩展。(?iLmsux)
(一组或多个字母
'i'
、'L'
、'm'
、's'
、'u'
、'x'
。 ) 组匹配空字符串; 字母设置相应的标志:re.I(忽略大小写),re.L(取决于语言环境),re.M(多行), re.S(点匹配所有)、re.U(Unicode 相关)和 re.X(详细),用于整个正则表达式。 (这些标志在 模块内容 中进行了描述。)如果您希望将标志作为正则表达式的一部分而不是将 标志 参数传递给 ,这将非常有用re.compile() 函数。请注意,
(?x)
标志会更改表达式的解析方式。 它应该首先在表达式字符串中使用,或者在一个或多个空白字符之后使用。 如果标志前有非空白字符,则结果未定义。(?:...)
常规括号的非捕获版本。 匹配括号内的任何正则表达式,但组 匹配的子字符串在执行匹配后无法检索或在模式后面引用。
(?P<name>...)
与常规括号类似,但组匹配的子字符串可通过符号组名 name 访问。 组名必须是有效的 Python 标识符,并且每个组名只能在正则表达式中定义一次。 符号组也是编号组,就好像该组没有命名一样。
命名组可以在三种上下文中引用。 如果模式是
(?P<quote>['"]).*?(?P=quote)
(即 匹配用单引号或双引号引用的字符串):引用组“引用”的上下文
参考方法
在相同的模式本身
(?P=quote)
(如图)\1
处理匹配对象时
m
m.group('quote')
m.end('quote')
(等)
在传递给
re.sub()
的repl
参数的字符串中\g<quote>
\g<1>
\1
(?P=name)
对命名组的反向引用; 它匹配名为 name 的较早组匹配的任何文本。
(?#...)
A comment; the contents of the parentheses are simply ignored.
(?=...)
如果
...
下一个匹配,则匹配,但不消耗任何字符串。 这称为先行断言。 例如,Isaac (?=Asimov)
仅在其后跟'Asimov'
时才会匹配'Isaac '
。(?!...)
如果
...
下一个不匹配,则匹配。 这是一个否定的前瞻断言。 例如,Isaac (?!Asimov)
将匹配'Isaac '
仅当它是 not 后跟'Asimov'
。(?<=...)
如果字符串中的当前位置前面是在当前位置结束的
...
匹配项,则匹配。 这称为 肯定的后视断言 。(?<=abc)def
将在abcdef
中找到匹配项,因为lookbehind 将备份 3 个字符并检查包含的模式是否匹配。 包含的模式必须只匹配某些固定长度的字符串,这意味着abc
或a|b
是允许的,但a*
和a{3,4}
不是。 即使组引用匹配某些固定长度的字符串,也不支持它们。 请注意,以肯定的后视断言开头的模式将不匹配正在搜索的字符串的开头; 您很可能希望使用 search() 函数而不是 match() 函数:>>> import re >>> m = re.search('(?<=abc)def', 'abcdef') >>> m.group(0) 'def'
此示例查找连字符后的单词:
>>> m = re.search('(?<=-)\w+', 'spam-egg') >>> m.group(0) 'egg'
(?<!...)
如果字符串中的当前位置前面没有
...
的匹配项,则匹配。 这称为 否定后视断言 。 与正向后视断言类似,包含的模式必须只匹配某个固定长度的字符串,并且不应包含组引用。 以否定的后视断言开头的模式可能会在被搜索字符串的开头匹配。(?(id/name)yes-pattern|no-pattern)
如果具有给定 id 或 name 的组存在,将尝试与
yes-pattern
匹配,如果不存在,则与no-pattern
匹配。no-pattern
是可选的,可以省略。 例如,(<)?(\w+@\w+(?:\.\w+)+)(?(1)>)
是一个糟糕的电子邮件匹配模式,它将与'<user@host.com>'
以及'user@host.com'
匹配,但不能与'<user@host.com'
匹配。2.4 版中的新功能。
特殊序列由 '\'
和下表中的一个字符组成。 如果普通字符不在列表中,则生成的 RE 将匹配第二个字符。 例如,\$
匹配字符 '$'
。
\number
- 匹配相同号码组的内容。 组从 1 开始编号。 例如,
(.+) \1
匹配'the the'
或'55 55'
,但不匹配'thethe'
(注意组后面的空格)。 此特殊序列只能用于匹配前 99 个组中的一个。 如果 number 的第一位为 0,或者 number 是 3 个八进制数字,则不会被解释为组匹配,而是被解释为具有八进制值 number 的字符。 在字符类的'['
和']'
内,所有数字转义都被视为字符。 \A
- 仅在字符串的开头匹配。
\b
- 匹配空字符串,但仅在单词的开头或结尾。 单词被定义为一系列字母数字或下划线字符,因此单词的结尾由空格或非字母数字、非下划线字符表示。 请注意,形式上,
\b
被定义为\w
和\W
字符之间的边界(反之亦然),或\w
和开头/字符串的末尾,因此被视为字母数字的精确字符集取决于UNICODE
和LOCALE
标志的值。 例如,r'\bfoo\b'
匹配'foo'
、'foo.'
、'(foo)'
、'bar foo baz'
但不匹配'foobar'
或 [ X104X]。 在字符范围内,\b
表示退格字符,以与 Python 的字符串文字兼容。 \B
- 匹配空字符串,但仅当它在单词的开头或结尾处为 而非 时。 这意味着
r'py\B'
匹配'python'
、'py3'
、'py2'
,但不匹配'py'
、'py.'
或'py!'
。\B
与\b
正好相反,所以也受LOCALE
和UNICODE
的设定影响。 \d
- 当未指定 UNICODE 标志时,匹配任何十进制数字; 这相当于集合
[0-9]
。 使用 UNICODE,它将匹配 Unicode 字符属性数据库中归类为十进制数字的任何内容。 \D
- 当未指定 UNICODE 标志时,匹配任何非数字字符; 这相当于集合
[^0-9]
。 使用 UNICODE,它将匹配 Unicode 字符属性数据库中标记为数字的字符以外的任何字符。 \s
- 当未指定 UNICODE 标志时,它匹配任何空白字符,这等效于设置
[ \t\n\r\f\v]
。 LOCALE 标志对空间匹配没有额外影响。 如果设置了 UNICODE,这将匹配字符[ \t\n\r\f\v]
加上在 Unicode 字符属性数据库中归类为空格的任何内容。 \S
- 当未指定 UNICODE 标志时,匹配任何非空白字符; 这相当于设置
[^ \t\n\r\f\v]
LOCALE 标志对非空白匹配没有额外影响。 如果设置了 UNICODE,则匹配任何未在 Unicode 字符属性数据库中标记为空格的字符。 \w
- 当未指定 LOCALE 和 UNICODE 标志时,匹配任何字母数字字符和下划线; 这相当于集合
[a-zA-Z0-9_]
。 使用 LOCALE,它将匹配集合[0-9_]
加上任何定义为当前语言环境的字母数字的字符。 如果设置了 UNICODE,这将匹配字符[0-9_]
加上在 Unicode 字符属性数据库中归类为字母数字的任何内容。 \W
- 当未指定 LOCALE 和 UNICODE 标志时,匹配任何非字母数字字符; 这相当于集合
[^a-zA-Z0-9_]
。 使用 LOCALE,它将匹配不在集合[0-9_]
中的任何字符,并且未定义为当前语言环境的字母数字。 如果设置了 UNICODE,这将匹配除[0-9_]
之外的任何字符以及在 Unicode 字符属性数据库中归类为非字母数字的字符。 \Z
- 仅在字符串末尾匹配。
如果特定序列的 LOCALE 和 UNICODE 标志都包含在内,则 LOCALE 标志首先生效,然后是 UNICODE。
Python 字符串文字支持的大多数标准转义符也被正则表达式解析器接受:
\a \b \f \n
\r \t \v \x
\\
(请注意,\b
用于表示单词边界,仅在字符类内部表示“退格”。)
八进制转义包含在有限的形式中:如果第一个数字是 0,或者如果有三个八进制数字,则认为是八进制转义。 否则,它是一个组引用。 至于字符串文字,八进制转义的长度总是最多三位数。
也可以看看
- 掌握正则表达式
- Jeffrey Friedl 撰写的关于正则表达式的书,由 O'Reilly 出版。 本书的第二版根本不再涉及 Python,但第一版非常详细地涵盖了编写良好的正则表达式模式。
7.2.2. 模块内容
该模块定义了几个函数、常量和一个异常。 一些函数是编译正则表达式的全功能方法的简化版本。 大多数重要的应用程序总是使用编译形式。
- re.compile(pattern, flags=0)
将正则表达式模式编译为正则表达式对象,该对象可用于使用其 match() 和 search() 方法进行匹配,如下所述。
可以通过指定 flags 值来修改表达式的行为。 值可以是以下任何变量,使用按位或(
|
运算符)组合。序列
prog = re.compile(pattern) result = prog.match(string)
相当于
result = re.match(pattern, string)
但是当表达式将在单个程序中多次使用时,使用 re.compile() 并保存生成的正则表达式对象以供重用会更有效。
笔记
传递给 re.match()、re.search() 或 re.compile() 的最新模式的编译版本被缓存,因此程序一次只使用几个正则表达式的人不必担心编译正则表达式。
- re.DEBUG
- 显示有关编译表达式的调试信息。
- re.I
re.IGNORECASE
- 执行不区分大小写的匹配; 像
[A-Z]
这样的表达式也会匹配小写字母。 这不受当前语言环境的影响。 要在非 ASCII Unicode 字符(例如ü
和Ü
)上获得这种效果,请添加 UNICODE 标志。
- 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 字符属性数据库。 还为 IGNORECASE 启用非 ASCII 匹配。2.0 版中的新功能。
- re.X
re.VERBOSE 此标志允许您通过允许您在视觉上分隔模式的逻辑部分并添加注释来编写看起来更好且更具可读性的正则表达式。 模式中的空格会被忽略,除非在字符类中,或者前面有未转义的反斜杠,或者在
*?
、(?:
或(?P<...>
之类的标记中。 当一行包含不在字符类中且前面没有未转义反斜杠的#
时,从最左边的#
到行尾的所有字符都将被忽略。这意味着以下两个匹配十进制数的正则表达式对象在功能上是相等的:
a = re.compile(r"""\d + # the integral part \. # the decimal point \d * # some fractional digits""", re.X) b = re.compile(r"\d+\.\d*")
- re.search(pattern, string, flags=0)
- 扫描 string 查找正则表达式 pattern 产生匹配的第一个位置,并返回相应的 MatchObject 实例。 如果字符串中没有位置与模式匹配,则返回
None
; 请注意,这与在字符串中的某个点找到零长度匹配不同。
- re.match(pattern, string, flags=0)
如果 string 开头的零个或多个字符与正则表达式 pattern 匹配,则返回相应的 MatchObject 实例。 如果字符串与模式不匹配,则返回
None
; 请注意,这与零长度匹配不同。请注意,即使在 MULTILINE 模式下,re.match() 也只会匹配字符串的开头,而不匹配每行的开头。
如果你想在任何地方找到匹配细绳 , 用搜索() 相反(另见搜索()与 比赛() )。
- re.split(pattern, string, maxsplit=0, flags=0)
通过 模式 的出现拆分 字符串 。 如果在 pattern 中使用捕获括号,则模式中所有组的文本也会作为结果列表的一部分返回。 如果 maxsplit 不为零,则最多发生 maxsplit 次拆分,并且字符串的其余部分作为列表的最后一个元素返回。 (不兼容说明:在原始 Python 1.5 版本中,maxsplit 被忽略。 这已在以后的版本中修复。)
>>> re.split('\W+', 'Words, words, words.') ['Words', 'words', 'words', ''] >>> re.split('(\W+)', 'Words, words, words.') ['Words', ', ', 'words', ', ', 'words', '.', ''] >>> re.split('\W+', 'Words, words, words.', 1) ['Words', 'words, words.'] >>> re.split('[a-f]+', '0a3B9', flags=re.IGNORECASE) ['0', '3', '9']
如果分隔符中有捕获组并且它在字符串的开头匹配,则结果将以空字符串开头。 这同样适用于字符串的结尾:
>>> re.split('(\W+)', '...words, words...') ['', '...', 'words', ', ', 'words', '...', '']
这样,分隔符组件总是在结果列表中的相同相对索引处找到(例如,如果分隔符中有一个捕获组,则第 0 个、第 2 个等等)。
请注意, split 永远不会在空模式匹配上拆分字符串。 例如:
>>> re.split('x*', 'foo') ['foo'] >>> re.split("(?m)^$", "foo\n\nbar\n") ['foo\n\nbar\n']
在 2.7 版更改: 添加了可选的标志参数。
- re.findall(pattern, string, flags=0)
以字符串列表的形式返回 string 中 pattern 的所有非重叠匹配项。 string 从左到右扫描,并按找到的顺序返回匹配项。 如果模式中存在一个或多个组,则返回组列表; 如果模式有多个组,这将是一个元组列表。 结果中包含空匹配项。
笔记
由于当前实现的限制,空匹配之后的字符不包含在下一个匹配中,因此
findall(r'^|\w+', 'two words')
返回[, 'wo', 'words']
(注意错过了“t”)。 这在 Python 3.7 中有所改变。1.5.2 版中的新功能。
在 2.4 版更改: 添加了可选的标志参数。
- re.finditer(pattern, string, flags=0)
返回一个 iterator,在 string 中 RE pattern 的所有非重叠匹配上产生 MatchObject 实例。 string 从左到右扫描,并按找到的顺序返回匹配项。 结果中包含空匹配项。 另请参阅有关 findall() 的注释。
2.2 版中的新功能。
在 2.4 版更改: 添加了可选的标志参数。
- re.sub(pattern, repl, string, count=0, flags=0)
返回通过替换 repl 替换 string 中 pattern 最左边非重叠出现的字符串。 如果未找到模式,则返回 string 不变。 repl 可以是字符串也可以是函数; 如果它是一个字符串,则处理其中的任何反斜杠转义。 即,
\n
转换为单个换行符,\r
转换为回车,依此类推。 诸如\j
之类的未知转义被单独留下。 反向引用,例如\6
,被替换为模式中第 6 组匹配的子字符串。 例如:>>> re.sub(r'def\s+([a-zA-Z_][a-zA-Z_0-9]*)\s*\(\s*\):', ... r'static PyObject*\npy_\1(void)\n{', ... 'def myfunc():') 'static PyObject*\npy_myfunc(void)\n{'
如果 repl 是一个函数,它会在 pattern 的每次非重叠出现时调用。 该函数采用单个匹配对象参数,并返回替换字符串。 例如:
>>> def dashrepl(matchobj): ... if matchobj.group(0) == '-': return ' ' ... else: return '-' >>> re.sub('-{1,2}', dashrepl, 'pro----gram-files') 'pro--gram files' >>> re.sub(r'\sAND\s', ' & ', 'Baked Beans And Spam', flags=re.IGNORECASE) 'Baked Beans & Spam'
模式可以是字符串或 RE 对象。
可选参数 count 是要替换的模式出现的最大次数; count 必须是非负整数。 如果省略或为零,则将替换所有出现的内容。 模式的空匹配仅在与前一个匹配不相邻时才被替换,因此
sub('x*', '-', 'abc')
返回'-a-b-c-'
。在字符串类型 repl 参数中,除了上述字符转义和反向引用外,
\g<name>
将使用名为name
的组匹配的子字符串,如定义(?P<name>...)
语法。\g<number>
使用对应的组号;\g<2>
因此等价于\2
,但在\g<2>0
之类的替换中并不含糊。\20
将被解释为对组 20 的引用,而不是对组 2 的引用,后跟文字字符'0'
。 反向引用\g<0>
替换了 RE 匹配的整个子字符串。在 2.7 版更改: 添加了可选的标志参数。
- re.subn(pattern, repl, string, count=0, flags=0)
执行与 sub() 相同的操作,但返回一个元组
(new_string, number_of_subs_made)
。在 2.7 版更改: 添加了可选的标志参数。
- re.escape(pattern)
转义 pattern 中除 ASCII 字母和数字以外的所有字符。 如果您想匹配可能包含正则表达式元字符的任意文字字符串,这将非常有用。 例如:
>>> print re.escape('python.exe') python\.exe >>> legal_chars = string.ascii_lowercase + string.digits + "!#$%&'*+-.^_`|~:" >>> print '[%s]+' % re.escape(legal_chars) [abcdefghijklmnopqrstuvwxyz0123456789\!\#\$\%\&\'\*\+\-\.\^\_\`\|\~\:]+ >>> operators = ['+', '-', '*', '/', '**'] >>> print '|'.join(map(re.escape, sorted(operators, reverse=True))) \/|\-|\+|\*\*|\*
- re.purge()
- 清除正则表达式缓存。
- exception re.error
- 当传递给此处函数之一的字符串不是有效的正则表达式(例如,它可能包含不匹配的括号)或在编译或匹配期间发生其他一些错误时引发异常。 如果字符串不包含与模式匹配的内容,则永远不会出错。
7.2.3. 正则表达式对象
- class re.RegexObject
RegexObject 类支持以下方法和属性:
- search(string[, pos[, endpos]])
扫描 string 查找此正则表达式产生匹配的位置,并返回相应的 MatchObject 实例。 如果字符串中没有位置与模式匹配,则返回
None
; 请注意,这与在字符串中的某个点找到零长度匹配不同。可选的第二个参数 pos 给出字符串中开始搜索的索引; 默认为
0
。 这并不完全等同于对字符串进行切片;'^'
模式字符在字符串的真正开头和换行符之后的位置匹配,但不一定在搜索开始的索引处。可选参数 endpos 限制字符串的搜索范围; 就好像字符串是 endpos 个字符长,所以只有从 pos 到
endpos - 1
的字符会被搜索匹配。 如果 endpos 小于 pos,则找不到匹配项,否则,如果 rx 是编译后的正则表达式对象,则rx.search(string, 0, 50)
等价rx.search(string[:50], 0)
。>>> pattern = re.compile("d") >>> pattern.search("dog") # Match at index 0 <_sre.SRE_Match object at ...> >>> pattern.search("dog", 1) # No match; search doesn't include the "d"
- match(string[, pos[, endpos]])
如果 string 的 beginning 处的零个或多个字符与此正则表达式匹配,则返回相应的 MatchObject 实例。 如果字符串与模式不匹配,则返回
None
; 请注意,这与零长度匹配不同。可选的 pos 和 endpos 参数与 search() 方法具有相同的含义。
>>> pattern = re.compile("o") >>> pattern.match("dog") # No match as "o" is not at the start of "dog". >>> pattern.match("dog", 1) # Match as "o" is the 2nd character of "dog". <_sre.SRE_Match object at ...>
如果你想在任何地方找到匹配细绳 , 用搜索() 相反(另见搜索()与 比赛() )。
- split(string, maxsplit=0)
与 split() 函数相同,使用编译模式。
- finditer(string[, pos[, endpos]])
类似于 finditer() 函数,使用编译模式,但也接受可选的 pos 和 endpos 参数来限制搜索区域,例如 match ()。
- sub(repl, string, count=0)
与 sub() 函数相同,使用编译模式。
- subn(repl, string, count=0)
与 subn() 函数相同,使用编译模式。
- flags
正则表达式匹配标志。 这是给予 compile() 的标志和模式中任何
(?...)
内联标志的组合。
- groups
模式中捕获组的数量。
- groupindex
将
(?P<id>)
定义的任何符号组名称映射到组编号的字典。 如果模式中没有使用符号组,则字典为空。
- pattern
从中编译 RE 对象的模式字符串。
7.2.4. 匹配对象
- class re.MatchObject
匹配对象的布尔值始终为
True
。 由于match()
和search()
在不匹配时返回None
,您可以使用简单的if
语句测试是否匹配:match = re.search(pattern, string) if match: process(match)
匹配对象支持以下方法和属性:
- expand(template)
返回通过对模板字符串 template 执行反斜杠替换获得的字符串,如 sub() 方法所做的那样。 转义如
\n
被转换为适当的字符,数字反向引用 (\1
,\2
) 和命名反向引用 (\g<1>
,\g<name>
]) 被相应组的内容替换。
- group([group1, ...])
返回匹配的一个或多个子组。 如果只有一个参数,则结果是一个字符串; 如果有多个参数,则结果是一个元组,每个参数一个项目。 没有参数, group1 默认为零(返回整个匹配项)。 如果 groupN 参数为零,则对应的返回值是整个匹配字符串; 如果在包含范围[1..99]内,则为与相应括号组匹配的字符串。 如果组号为负数或大于模式中定义的组数,则会引发
IndexError
异常。 如果某个组包含在不匹配的模式部分中,则对应的结果为None
。 如果某个组包含在多次匹配的模式部分中,则返回最后一个匹配项。>>> m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist") >>> m.group(0) # The entire match 'Isaac Newton' >>> m.group(1) # The first parenthesized subgroup. 'Isaac' >>> m.group(2) # The second parenthesized subgroup. 'Newton' >>> m.group(1, 2) # Multiple arguments give us a tuple. ('Isaac', 'Newton')
如果正则表达式使用
(?P<name>...)
语法,groupN 参数也可以是通过组名标识组的字符串。 如果字符串参数未用作模式中的组名,则会引发IndexError
异常。一个中等复杂的例子:
>>> m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "Malcolm Reynolds") >>> m.group('first_name') 'Malcolm' >>> m.group('last_name') 'Reynolds'
命名组也可以通过它们的索引来引用:
>>> m.group(1) 'Malcolm' >>> m.group(2) 'Reynolds'
如果一个组匹配多次,则只能访问最后一个匹配:
>>> m = re.match(r"(..)+", "a1b2c3") # Matches 3 times. >>> m.group(1) # Returns only the last match. 'c3'
- groups([default])
返回一个包含匹配所有子组的元组,从 1 到模式中有多少个组。 default 参数用于未参加比赛的组; 默认为
None
。 (不兼容说明:在最初的 Python 1.5 版本中,如果元组是一个元素长,则将返回一个字符串。 在以后的版本中(从 1.5.1 开始),在这种情况下会返回一个单例元组。)例如:
>>> m = re.match(r"(\d+)\.(\d+)", "24.1632") >>> m.groups() ('24', '1632')
如果我们将小数点及其后的所有内容设为可选,则并非所有组都可能参加比赛。 这些组将默认为
None
,除非给出 default 参数:>>> m = re.match(r"(\d+)\.?(\d+)?", "24") >>> m.groups() # Second group defaults to None. ('24', None) >>> m.groups('0') # Now, the second group defaults to '0'. ('24', '0')
- groupdict([default])
返回包含匹配的所有 named 子组的字典,以子组名称为键。 default 参数用于未参加比赛的组; 默认为
None
。 例如:>>> m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "Malcolm Reynolds") >>> m.groupdict() {'first_name': 'Malcolm', 'last_name': 'Reynolds'}
- start([group])
end([group]) 返回group匹配的子串首尾索引; group 默认为零(意味着整个匹配的子字符串)。 如果 group 存在但没有参与比赛,则返回
-1
。 对于匹配对象 m 和对匹配有贡献的组 g,组 g(相当于m.group(g)
)匹配的子串) 是m.string[m.start(g):m.end(g)]
请注意,如果 group 匹配空字符串,则
m.start(group)
将等于m.end(group)
。 例如m = re.search('b(c?)', 'cba')
后,m.start(0)
为1,m.end(0)
为2,m.start(1)
和m.end(1)
均为2,m.start(2)
引发IndexError
异常。从电子邮件地址中删除 remove_this 的示例:
>>> email = "tony@tiremove_thisger.net" >>> m = re.search("remove_this", email) >>> email[:m.start()] + email[m.end():] 'tony@tiger.net'
- span([group])
对于 MatchObject m,返回二元组
(m.start(group), m.end(group))
。 请注意,如果 group 对比赛没有贡献,则为(-1, -1)
。 group 默认为零,整个匹配。
- pos
传递给 RegexObject 的 search() 或 match() 方法的 pos 的值。 这是 RE 引擎开始寻找匹配的字符串的索引。
- endpos
传递给 RegexObject 的 search() 或 match() 方法的 endpos 的值。 这是 RE 引擎不会超过的字符串索引。
- lastindex
最后匹配的捕获组的整数索引,如果根本没有匹配的组,则为
None
。 例如,表达式(a)b
、((a)(b))
和((ab))
如果应用于字符串'ab'
将具有lastindex == 1
,而表达式 [ X142X] 将有lastindex == 2
,如果应用于相同的字符串。
- lastgroup
最后匹配的捕获组的名称,如果组没有名称,或者根本没有匹配的组,则为
None
。
- re
正则表达式对象的 match() 或 search() 方法产生了这个 MatchObject 实例。
7.2.5. 例子
7.2.5.1. 检查一对
在这个例子中,我们将使用以下辅助函数来更优雅地显示匹配对象:
def displaymatch(match):
if match is None:
return None
return '<Match: %r, groups=%r>' % (match.group(), match.groups())
假设您正在编写一个扑克程序,其中玩家的手牌表示为 5 个字符的字符串,每个字符代表一张牌,“a”代表 A,“k”代表国王,“q”代表皇后,“j”代表 jack, “t”代表 10,“2”到“9”代表具有该值的卡片。
要查看给定的字符串是否有效,可以执行以下操作:
>>> valid = re.compile(r"^[a2-9tjqk]{5}$")
>>> displaymatch(valid.match("akt5q")) # Valid.
"<Match: 'akt5q', groups=()>"
>>> displaymatch(valid.match("akt5e")) # Invalid.
>>> displaymatch(valid.match("akt")) # Invalid.
>>> displaymatch(valid.match("727ak")) # Valid.
"<Match: '727ak', groups=()>"
最后一手牌 "727ak"
包含一对或两张价值相同的牌。 要将其与正则表达式匹配,可以使用反向引用:
>>> pair = re.compile(r".*(.).*\1")
>>> displaymatch(pair.match("717ak")) # Pair of 7s.
"<Match: '717', groups=('7',)>"
>>> displaymatch(pair.match("718ak")) # No pairs.
>>> displaymatch(pair.match("354aa")) # Pair of aces.
"<Match: '354aa', groups=('a',)>"
要找出这对卡片由什么卡片组成,可以按以下方式使用 MatchObject 的 group() 方法:
>>> pair.match("717ak").group(1)
'7'
# Error because re.match() returns None, which doesn't have a group() method:
>>> pair.match("718ak").group(1)
Traceback (most recent call last):
File "<pyshell#23>", line 1, in <module>
re.match(r".*(.).*\1", "718ak").group(1)
AttributeError: 'NoneType' object has no attribute 'group'
>>> pair.match("354aa").group(1)
'a'
7.2.5.2. 模拟 scanf()
Python 目前没有与 scanf()
等效的东西。 正则表达式通常比 scanf()
格式字符串更强大,但也更冗长。 下表提供了 scanf()
格式标记和正则表达式之间或多或少的等效映射。
scanf() 代币
|
正则表达式 |
---|---|
%c
|
.
|
%5c
|
.{5}
|
%d
|
[-+]?\d+
|
%e 、%E 、%f 、%g
|
\.\d+)([eE][-+]?\d+)? |
%i
|
0[0-7]*|\d+) |
%o
|
[-+]?[0-7]+
|
%s
|
\S+
|
%u
|
\d+
|
%x 、%X
|
[-+]?(0[xX])?[\dA-Fa-f]+
|
从像这样的字符串中提取文件名和数字
/usr/sbin/sendmail - 0 errors, 4 warnings
您将使用 scanf()
格式,例如
%s - %d errors, %d warnings
等效的正则表达式是
(\S+) - (\d+) errors, (\d+) warnings
7.2.5.3. 搜索()与 比赛()
Python 提供了两种不同的基于正则表达式的原始操作: re.match() 只在字符串的开头检查匹配,而 re.search() 检查匹配字符串中的任何位置(这是 Perl 默认所做的)。
例如:
>>> re.match("c", "abcdef") # No match
>>> re.search("c", "abcdef") # Match
<_sre.SRE_Match object at ...>
以 '^'
开头的正则表达式可以与 search() 一起使用来限制字符串开头的匹配:
>>> re.match("c", "abcdef") # No match
>>> re.search("^c", "abcdef") # No match
>>> re.search("^a", "abcdef") # Match
<_sre.SRE_Match object at ...>
但请注意,在 MULTILINE 模式下,match() 仅匹配字符串的开头,而使用 search() 和以 '^'
将在每行的开头匹配。
>>> re.match('X', 'A\nB\nX', re.MULTILINE) # No match
>>> re.search('^X', 'A\nB\nX', re.MULTILINE) # Match
<_sre.SRE_Match object at ...>
7.2.5.4. 制作电话簿
split() 将字符串拆分为由传递的模式分隔的列表。 该方法对于将文本数据转换为可由 Python 轻松读取和修改的数据结构非常有用,如以下创建电话簿的示例所示。
首先,这是输入。 通常它可能来自一个文件,这里我们使用三引号字符串语法:
>>> text = """Ross McFluff: 834.345.1254 155 Elm Street
...
... Ronald Heathmore: 892.345.3428 436 Finley Avenue
... Frank Burger: 925.541.7625 662 South Dogwood Way
...
...
... Heather Albrecht: 548.326.4584 919 Park Place"""
条目由一个或多个换行符分隔。 现在我们将字符串转换为一个列表,每个非空行都有自己的条目:
>>> entries = re.split("\n+", text)
>>> entries
['Ross McFluff: 834.345.1254 155 Elm Street',
'Ronald Heathmore: 892.345.3428 436 Finley Avenue',
'Frank Burger: 925.541.7625 662 South Dogwood Way',
'Heather Albrecht: 548.326.4584 919 Park Place']
最后,将每个条目拆分为一个包含名字、姓氏、电话号码和地址的列表。 我们使用 split() 的 maxsplit
参数,因为地址中有空格,即我们的拆分模式:
>>> [re.split(":? ", entry, 3) for entry in entries]
[['Ross', 'McFluff', '834.345.1254', '155 Elm Street'],
['Ronald', 'Heathmore', '892.345.3428', '436 Finley Avenue'],
['Frank', 'Burger', '925.541.7625', '662 South Dogwood Way'],
['Heather', 'Albrecht', '548.326.4584', '919 Park Place']]
:?
模式匹配姓氏后面的冒号,因此它不会出现在结果列表中。 使用 maxsplit
的 4
,我们可以将门牌号与街道名称分开:
>>> [re.split(":? ", entry, 4) for entry in entries]
[['Ross', 'McFluff', '834.345.1254', '155', 'Elm Street'],
['Ronald', 'Heathmore', '892.345.3428', '436', 'Finley Avenue'],
['Frank', 'Burger', '925.541.7625', '662', 'South Dogwood Way'],
['Heather', 'Albrecht', '548.326.4584', '919', 'Park Place']]
7.2.5.5. 文本处理
sub() 用字符串或函数的结果替换模式的每次出现。 这个例子演示了使用 sub() 和一个函数来“处理”文本,或者随机化一个句子的每个单词中除了第一个和最后一个字符之外的所有字符的顺序:
>>> def repl(m):
... inner_word = list(m.group(2))
... random.shuffle(inner_word)
... return m.group(1) + "".join(inner_word) + m.group(3)
>>> text = "Professor Abdolmalek, please report your absences promptly."
>>> re.sub(r"(\w)(\w+)(\w)", repl, text)
'Poefsrosr Aealmlobdk, pslaee reorpt your abnseces plmrptoy.'
>>> re.sub(r"(\w)(\w+)(\w)", repl, text)
'Pofsroser Aodlambelk, plasee reoprt yuor asnebces potlmrpy.'
7.2.5.6. 查找所有副词
findall() 匹配 all 模式的出现,而不是像 search() 那样只匹配第一个。 例如,如果作者想在某些文本中找到所有副词,他们可以按以下方式使用 findall():
>>> text = "He was carefully disguised but captured quickly by police."
>>> re.findall(r"\w+ly", text)
['carefully', 'quickly']
7.2.5.7. 查找所有副词及其位置
如果你想要比匹配文本更多的关于模式的所有匹配的信息,finditer() 很有用,因为它提供了 MatchObject 的实例而不是字符串。 继续前面的例子,如果作者想在一些文本中找到所有的副词 和它们的位置 ,他们会以下列方式使用 finditer():
>>> text = "He was carefully disguised but captured quickly by police."
>>> for m in re.finditer(r"\w+ly", text):
... print '%02d-%02d: %s' % (m.start(), m.end(), m.group(0))
07-16: carefully
40-47: quickly
7.2.5.8. 原始字符串表示法
原始字符串表示法 (r"text"
) 使正则表达式保持理智。 没有它,正则表达式中的每个反斜杠 ('\'
) 都必须以另一个反斜杠为前缀才能转义它。 例如,以下两行代码在功能上是相同的:
>>> re.match(r"\W(.)\1\W", " ff ")
<_sre.SRE_Match object at ...>
>>> re.match("\\W(.)\\1\\W", " ff ")
<_sre.SRE_Match object at ...>
当想要匹配文字反斜杠时,必须在正则表达式中对其进行转义。 使用原始字符串表示法,这意味着 r"\\"
。 如果没有原始字符串表示法,必须使用 "\\\\"
,使以下代码行在功能上相同:
>>> re.match(r"\\", r"\\")
<_sre.SRE_Match object at ...>
>>> re.match("\\\\", r"\\")
<_sre.SRE_Match object at ...>