7.2. re-正则表达式运算

该模块提供与 Perl 中类似的正则表达式匹配操作。模式和要搜索的字符串都可以是 Unicode 字符串以及 8 位字符串。

正则表达式使用反斜杠字符('\')表示特殊形式或允许使用特殊字符而无需调用特殊含义。这与 Python 在字符串 Literals 中出于相同目的使用相同字符的目的相冲突。例如,要匹配 Literals 反斜杠,可能必须写'\\\\'作为模式字符串,因为正则表达式必须为\\,并且每个反斜杠必须在常规 Python 字符串 Literals 中表示为\\

解决方案是将 Python 的原始字符串表示法用于正则表达式模式。反斜杠不会以任何特殊方式处理以'r'开头的字符串 Literals。因此r"\n"是一个包含'\''n'的两个字符的字符串,而"\n"是一个包含换行符的一个单字符的字符串。通常,模式将使用此原始字符串表示法在 Python 代码中表示。

重要的是要注意,大多数正则表达式操作都可以作为模块级函数和RegexObject方法使用。这些函数是快捷方式,不需要您首先编译一个 regex 对象,但是会错过一些微调参数。

See also

第三方regex模块具有与标准库re模块兼容的 API,但是提供了附加Function和更全面的 Unicode 支持。

7.2.1. 正则表达式语法

正则表达式(或 RE)指定一组与之匹配的字符串;该模块中的函数可让您检查特定字符串是否与给定的正则表达式匹配(或给定的正则表达式是否与特定的字符串匹配,这取决于同一件事)。

可以将正则表达式连接起来以形成新的正则表达式。如果* A B 都是正则表达式,则 AB 也是正则表达式。通常,如果字符串 p 匹配 A ,而另一个字符串 q 匹配 B ,则字符串 pq 将匹配 AB。除非 A B *包含低优先级运算,否则这将成立。 * A B *之间的边界条件;或具有编号的组引用。因此,可以从简单的原始表达式(如此处所述的表达式)轻松构造复杂的表达式。有关正则表达式的理论和实现的详细信息,请参阅上面引用的 Friedl 书或几乎所有有关编译器构造的教科书。

下面是对正则表达式格式的简要说明。有关更多信息和更柔和的介绍,请查阅正则表达式操作方法

正则表达式可以包含特殊字符和普通字符。大多数普通字符(例如'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>。在限定符之后加上?使其以非贪婪最小的方式执行匹配;因为最少个字符将被匹配。使用 RE <.*?>仅匹配<a>
  • {m}

    • 指定应该完全匹配先前 RE 的* m *个副本;较少的匹配会导致整个 RE 不匹配。例如,a{6}将完全匹配六个'a'字符,但不能完全匹配五个。
  • {m,n}

    • 使结果 RE 匹配先前 RE 的* m n 个重复,并try匹配尽可能多的重复。例如,a{3,5}将匹配 3 到 5 'a'个字符。Ellipsis m 指定下限为零,Ellipsis n *指定无限上限。例如,a{4,}b将匹配aaaab或一千个'a'字符,后跟b,但不匹配aaab。逗号不能Ellipsis,否则修饰符会与前面描述的形式混淆。
  • {m,n}?

    • 使结果 RE 匹配先前 RE 的* m n 个重复,并try尽可能少地匹配*。这是前一个限定词的非贪婪版本。例如,在 6 个字符的字符串'aaaaaa'上,a{3,5}将匹配 5 个'a'字符,而a{3,5}?将仅匹配 3 个字符。
  • '\'

    • 要么转义特殊字符(允许您匹配'*''?'等字符),要么发出特殊序列的 signal;或者特殊序列将在下面讨论。

如果您不使用原始字符串来表达模式,请记住 Python 还使用反斜杠作为字符串 Literals 中的转义序列。如果 Python 的解析器无法识别转义序列,则结果字符串中将包含反斜杠和后续字符。但是,如果 Python 将识别出结果序列,则应将反斜杠重复两次。这是复杂且难以理解的,因此强烈建议您对除最简单的表达式以外的所有表达式使用原始字符串。

  • []

    • 用于指示一组字符。在一组中:
  • 字符可以单独列出,例如[amk]将匹配'a''m''k'

  • 可以pass给出两个字符并用'-'隔开来表示字符范围,例如[a-z]将匹配任何小写 ASCII 字母,[0-5][0-9]将匹配从0059的所有两位数字,而[0-9A-Fa-f]将匹配任何十六进制数字。如果-被转义了(例如[a\-z]),或者被放置为第一个或最后一个字符(例如[a-]),它将与 Literals'-'匹配。

  • 特殊字符在集合内失去其特殊含义。例如,[(+*)]将匹配任何 Literals 字符'(''+''*'')'

  • 集合中也接受诸如\w\S之类的字符类(定义如下),尽管它们匹配的字符取决于生效的是LOCALE还是UNICODE模式。

  • 可以pass对集合进行“补充”来匹配不在范围内的字符。如果集合的第一个字符是'^',则集合中所有* not *的字符都将匹配。例如,[^5]将匹配'5'以外的任何字符,而[^^]将匹配'^'以外的任何字符。 ^不是集合中的第一个字符,则没有特殊含义。

  • 要匹配集合中的 Literals']',请在其前面加上反斜杠,或将其放在集合的开头。例如,[()[\]{}][]()[{}]都将匹配括号。

  • '|'

    • A|B(其中 A 和 B 可以是任意 RE)将创建一个与 A 或 B 匹配的正则表达式。pass'|'可以以这种方式分隔任意数量的 RE。也可以在组内使用(请参阅下文)。扫描目标字符串时,从左到右try用'|'分隔的 RE。当一个模式完全匹配时,该分支被接受。这意味着一旦A匹配,就不会进一步测试B,即使它将产生更长的整体匹配。换句话说,'|'运算符从不贪婪。要匹配 Literals'|',请使用\|,或将其包含在字符类中,如[|]所示。
  • (...)

    • 匹配括号内的任何正则表达式,并指示组的开始和结束;可以在执行匹配后检索组的内容,并且以后可以在字符串中使用\number特殊序列进行匹配,如下所述。要匹配 Literals'('')',请使用\(\),或将它们括在字符类[(] [)]中。
  • (?...)

    • 这是一个扩展符号(在'('之后的'?'否则没有意义)。 '?'之后的第一个字符确定该构造的含义和其他语法。扩展通常不会创建新的组。 (?P<name>...)是此规则的唯一 exception。以下是当前支持的扩展。
  • (?iLmsux)

    • (一组'i''L''m''s''u''x'中的一个或多个字母.)该组与空字符串匹配;字母为整个正则表达式设置了相应的标志:re.I(忽略大小写),re.L(与语言环境相关),re.M(多行),re.S(所有点都匹配),re.U(与 Unicode 相关)和re.X(详细) 。 (标志在Module Contents中描述。)如果您希望将标志包括在正则表达式中,而不是向re.compile()函数传递* flag *参数,则这很有用。

请注意,(?x)标志会更改表达式的解析方式。应该在表达式字符串中首先使用它,或者在一个或多个空格字符之后使用它。如果标志前有非空格字符,则结果不确定。

  • (?:...)

    • 非捕获版本的常规括号。匹配括号内的任何正则表达式,但执行匹配后无法检索由组*匹配的子字符串,或稍后在模式中引用。
  • (?P<name>...)

    • 与常规括号类似,但是可以pass符号组名* name *访问组匹配的子字符串。组名必须是有效的 Python 标识符,并且每个组名必须在正则表达式中仅定义一次。符号组也是带编号的组,就像未命名该组一样。

可以在三个上下文中引用命名组。如果格式为(?P<quote>['"]).*?(?P=quote)(即匹配用单引号或双引号引起来的字符串):

引用组“ quote”的上下文引用方式
以相同的模式(?P=quote)(如图所示)

\1
当处理匹配对象mm.group('quote')
m.end('quote')(等)
在传递给re.sub()repl参数的字符串中\g<quote>
\g<1>
\1
  • (?P=name)

    • 对命名组的反向引用;它匹配早期名为* name *的组匹配的任何文本。
  • (?#...)

    • 一条 Comment;括号中的内容将被忽略。
  • (?=...)

    • 如果...下一个匹配,则匹配,但不使用任何字符串。这称为先行 assert。例如,Isaac (?=Asimov)仅在其后跟'Asimov'时才匹配'Isaac '
  • (?!...)

    • 如果下一个...不匹配则匹配。这是一个否定的超前 assert。例如,Isaac (?!Asimov)仅当* not *后跟'Asimov'时才匹配'Isaac '
  • (?<=...)

    • 如果字符串的当前位置前面有...匹配项(在当前位置结束),则匹配。这称为肯定 assert(?<=abc)def将在abcdef中找到一个匹配项,因为后向搜索将备份 3 个字符并检查所包含的模式是否匹配。所包含的模式只能匹配某些固定长度的字符串,这意味着允许abca|b,但不允许a*a{3,4}。即使组引用匹配某个固定长度的字符串,也不支持组引用。注意,以正向后 assert 开头的模式在搜索字符串的开头将不匹配;您很可能想使用search()函数而不是match()函数:
>>> import re
>>> m = re.search('(?<=abc)def', 'abcdef')
>>> m.group(0)
'def'

本示例在连字符后查找单词:

>>> m = re.search('(?<=-)\w+', 'spam-egg')
>>> m.group(0)
'egg'
  • (?<!...)

    • 如果字符串的当前位置之前没有...的匹配项,则匹配。这称为assert 后 assert。与肯定的后置 assert 类似,所包含的模式必须仅匹配某个固定长度的字符串,并且不应包含组引用。以否定式后向 assert 开头的模式可能与要搜索的字符串的开头匹配。
  • (?(id/name)yes-pattern|no-pattern)

    • 如果存在具有给定* id name *的组,则try与yes-pattern匹配;如果不存在,则try与no-pattern匹配。 no-pattern是可选的,可以Ellipsis。例如,(<)?(\w+@\w+(?:\.\w+)+)(?(1)>)是较差的电子邮件匹配模式,它将与'<[email protected]>'以及'[email protected]'匹配,但不会与'<[email protected]'匹配。

2.4 版的新Function。

特殊序列由'\'和下面列表中的字符组成。如果普通字符不在列表中,则生成的 RE 将与第二个字符匹配。例如,\$匹配字符'$'

  • \number

    • 匹配相同编号组的内容。组从 1 开始编号。例如,(.+) \1匹配'the the''55 55',但不匹配'thethe'(请注意组后面的空格)。此特殊序列只能用于匹配前 99 个组之一。如果* number 的第一位数字为 0,或者 number 的长度为 3 个八进制数字,则不会将其解释为组匹配,而是将其解释为具有八进制值 number *的字符。在字符类的'['']'内,所有数字转义符均视为字符。
  • \A

    • 仅在字符串开头匹配。
  • \b

    • 匹配空字符串,但仅匹配单词的开头或结尾。单词定义为字母数字或下划线字符的序列,因此单词的结尾由空格或非字母数字,非下划线字符指示。请注意,在形式上,\b被定义为\w\W字符之间的边界(反之亦然),或\w与字符串的开头/结尾之间的边界,因此被视为字母数字的确切字符集取决于的值UNICODELOCALE标志。例如,r'\bfoo\b''foo''foo.''(foo)''bar foo baz'匹配,但与'foobar''foo3'不匹配。在字符范围内,\b表示退格字符,以与 Python 的字符串 Literals 兼容。
  • \B

    • 匹配空字符串,但仅当单词的开头或结尾不是*时才匹配。这意味着r'py\B''python''py3''py2'匹配,但与'py''py.''py!'不匹配。 \B\b相反,因此也要受LOCALEUNICODE的设置限制。
  • \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

    • 如果未指定LOCALEUNICODE标志,则匹配任何字母数字字符和下划线;这等效于[a-zA-Z0-9_]。使用LOCALE,它将匹配集合[0-9_]以及当前语言环境定义为字母数字的任何字符。如果设置了UNICODE,它将匹配字符[0-9_]以及 Unicode 字符属性数据库中分类为字母数字的任何字符。
  • \W

    • 如果未指定LOCALEUNICODE标志,则匹配任何非字母数字字符;这等效于[^a-zA-Z0-9_]。使用LOCALE,它将匹配集合[0-9_]中没有的任何字符,并且不将其定义为当前语言环境的字母数字。如果设置了UNICODE,则它将匹配[0-9_]以及 Unicode 字符属性数据库中归类为非字母数字字符之外的任何字符。
  • \Z

    • 仅在字符串末尾匹配。

如果特定序列同时包含LOCALEUNICODE标志,则LOCALE标志首先生效,然后是UNICODE

正则表达式解析器也接受 Python 字符串 Literals 支持的大多数标准转义:

\a      \b      \f      \n
\r      \t      \v      \x
\\

(请注意,\b用于表示单词边界,仅在字符类内部表示“退格”.)

八进制转义以有限的形式包括在内:如果第一个数字为 0,或者有三个八进制数字,则将其视为八进制转义。否则,它是一个组引用。对于字符串 Literals,八进制转义符的长度始终最多为三位数。

See also

  • 掌握正则表达式

  • 本书由 Jeffrey Friedl 撰写,由 O'Reilly 出版。该书的第二版不再涵盖 Python,但第一版则详细介绍了编写良好的正则表达式模式。

7.2.2. 模块内容

该模块定义了几个函数,常量和一个异常。其中一些Function是用于编译正则表达式的全Function方法的简化版本。大多数非平凡的应用程序始终使用已编译的表单。

  • re. compile(* pattern flags = 0 *)
    • 将正则表达式模式编译成正则表达式对象,可使用其match()search()方法进行匹配,如下所述。

可以pass指定* flags *值来修改表达式的行为。值可以是以下任何变量,可以使用按位或(|运算符)进行组合。

The sequence

prog = re.compile(pattern)
result = prog.match(string)

相当于

result = re.match(pattern, string)

但是,当在单个程序中多次使用表达式时,使用re.compile()并保存生成的正则表达式对象以供重用会更有效。

Note

传递给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 版中的新Function。

  • re. X
  • re. VERBOSE
    • 该标志允许您直观地分隔模式的逻辑部分并添加 Comments,从而使您可以编写看起来更美观,更易读的正则表达式。模式中的空格将被忽略,除非在字符类中,在未转义的反斜杠之前或在*?(?:(?P<...>之类的标记中。当一行中包含不是字符类中的#且没有未转义的反斜杠时,则从最左边的#到该行末尾的所有字符都将被忽略。

这意味着以下两个与十进制数匹配的正则表达式对象在Function上相等:

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()也只会在字符串的开头而不是每行的开头匹配。

如果要在* string *中的任何位置找到匹配项,请改用search()(另请参见search()与 match())。

  • re. split(* pattern string maxsplit = 0 flags = 0 *)
    • 用* pattern 的出现分割 string 。如果在 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 版中进行了更改:添加了可选的 flags 参数。

  • re. findall(* pattern string flags = 0 *)
    • 以字符串列表形式返回* string 中所有 pattern 的非重叠匹配。从左到右扫描 string *,并以找到的 Sequences 返回匹配项。如果模式中存在一个或多个组,则返回一个组列表;否则,返回一个列表。如果模式包含多个组,则这将是一个 Tuples 列表。空匹配项包含在结果中。

Note

由于当前实施方式的限制,在空匹配之后的字符不会包含在下一个匹配中,因此findall(r'^|\w+', 'two words')返回['', 'wo', 'words'](请注意缺少“ t”)。这在 Python 3.7 中已更改。

版本 1.5.2 中的新Function。

在版本 2.4 中进行了更改:添加了可选的 flags 参数。

  • re. finditer(* pattern string flags = 0 *)
    • 在* string *中的 RE * pattern 的所有不重叠匹配中返回iterator产生MatchObject个实例。从左到右扫描 string *,并以找到的 Sequences 返回匹配项。空匹配项包含在结果中。另请参阅有关findall()的 Comments。

2.2 版中的新Function。

在版本 2.4 中进行了更改:添加了可选的 flags 参数。

  • re. sub(* pattern repl string count = 0 flags = 0 *)
    • 返回pass用替换* 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 *的每次不重叠发生时都调用它。该函数采用单个 match 对象参数,并返回替换字符串。例如:

>>> 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 *必须为非负整数。如果Ellipsis或为零,将替换所有出现的事件。模式的空匹配仅在不与上一个匹配相邻时才被替换,因此sub('x*', '-', 'abc')返回'-a-b-c-'

在字符串类型* repl *参数中,除了上述的字符转义和反向引用外,\g<name>将使用由(?P<name>...)语法定义的,与名为name的组匹配的子字符串。 \g<number>使用相应的组号;因此,\g<2>等效于\2,但在诸如\g<2>0之类的替换中并没有歧义。 \20将被解释为对组 20 的引用,而不是对后跟 Literals 字符'0'的组 2 的引用。反向引用\g<0>替换 RE 匹配的整个子字符串。

在 2.7 版中进行了更改:添加了可选的 flags 参数。

  • re. subn(* pattern repl string count = 0 flags = 0 *)
    • 执行与sub()相同的操作,但返回 Tuples(new_string, number_of_subs_made)

在 2.7 版中进行了更改:添加了可选的 flags 参数。

  • re. escape(模式)
    • 转义* pattern *中的所有字符(ASCII 字母和数字除外)。如果要匹配可能包含正则表达式元字符的任意 Literals 字符串,这将很有用。例如:
>>> 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. 正则表达式对象

  • 类别 re. 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 ...>

如果要在* string *中的任何位置找到匹配项,请改用search()(另请参见search()与 match())。

  • split(* string maxsplit = 0 *)

    • split()函数相同,使用已编译的模式。
  • findall(* string * [,* pos * [,* endpos *]])

    • findall()函数类似,使用已编译的模式,但也接受可选的* pos endpos *参数,它们限制了搜索区域,例如match()
  • 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>)定义的任何符号组名 Map 到组号。如果模式中未使用任何符号组,则词典为空。
  • pattern

    • 从中编译 RE 对象的模式字符串。

7.2.4. 匹配对象

  • 类别 re. MatchObject
    • 匹配对象的布尔值始终为True。由于在没有匹配项时match()search()返回None,因此您可以使用简单的if语句来测试是否存在匹配项:
match = re.search(pattern, string)
if match:
    process(match)

匹配对象支持以下方法和属性:

  • expand(模板)

    • 返回pass对模板字符串* template *进行反斜杠替换而获得的字符串,就像sub()方法一样。诸如\n的转义符将转换为适当的字符,并且数字后向引用(\1\2)和命名后向引用(\g<1>\g<name>)被相应组的内容替换。
  • group([* group1 ... *])

    • 返回匹配项的一个或多个子组。如果有单个参数,则结果为单个字符串;否则,结果为单个字符串。如果有多个参数,则结果是一个 Tuples,每个参数有一个项目。没有参数,* group1 默认为零(返回整个匹配项)。如果 groupN *参数为零,则对应的返回值为整个匹配字符串;否则,返回值为 0.如果它在包含范围[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 *参数也可以是pass组名标识组的字符串。如果在模式中未将字符串参数用作组名,则会引发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'

命名组也可以pass其索引来引用:

>>> 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([默认])
    • 返回一个包含匹配项所有子组的 Tuples,从 1 到模式中的许多组。 * default *参数用于未参加 match 的组;默认为None。 (不兼容说明:在原始的 Python 1.5 版本中,如果 Tuples 是一个元素长,则将返回一个字符串.在更高版本中(从 1.5.1 开始),在这种情况下将返回单例 Tuples。)

For example:

>>> m = re.match(r"(\d+)\.(\d+)", "24.1632")
>>> m.groups()
('24', '1632')

如果我们将小数位及其后的所有内容设为可选,则并非所有组都可以参加 match。除非给出* default *参数,否则这些组将默认为None

>>> 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([默认])
    • 返回一个字典,其中包含该匹配项的所有* named *子组,并以子组名称为关键字。 * default *参数用于未参加 match 的组;默认为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():]
'[email protected]'
  • span([* group *])

    • 对于MatchObject * m ,返回 2Tuples(m.start(group), m.end(group))。请注意,如果 group *没有参与 match,则为(-1, -1)。 * group *默认为零,即整个匹配。
  • pos

  • endpos

  • lastindex

    • 最后一个匹配的捕获组的整数索引;如果根本没有匹配的组,则返回None。例如,表达式(a)b((a)(b))((ab))如果应用于字符串'ab'将具有lastindex == 1,而表达式(a)(b)如果应用于同一字符串将具有lastindex == 2
  • lastgroup

    • 最后匹配的捕获组的名称;如果该组没有名称,或者根本没有匹配的组,则返回None
  • re

  • string

7.2.5. Examples

7.2.5.1. 检查Pair

在此示例中,我们将使用以下帮助函数来更优雅地显示匹配对象:

def displaymatch(match):
    if match is None:
        return None
    return '<Match: %r, groups=%r>' % (match.group(), match.groups())

假设您正在编写一个扑克程序,其中玩家的手用 5 个字符的字符串表示,每个字符代表一张纸牌,“ a”代表 ace,“ k”代表国王,“ q”代表皇后,“ j”代表杰克, “ 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或两个相同值的卡。为了将其与正则表达式匹配,可以使用如下反向引用:

>>> 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',)>"

要找出两人组成的卡,可以pass以下方式使用MatchObjectgroup()方法:

>>> 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()格式标记和正则表达式之间的等效 Map。

scanf()令牌Regular Expression
%c.
%5c.{5}
%d[-+]?\d+
%e , %E , %f , %g[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?
%i[-+]?(0[xX][\dA-Fa-f]+|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. search()与 match()

Python 根据正则表达式提供了两种不同的基本操作:re.match()仅在字符串的开头检查匹配项,而re.search()在字符串的任何位置检查匹配项(这是 Perl 的默认设置)。

For example:

>>> 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 轻松读取和修改的数据结构非常有用,如以下创建电话簿的示例所示。

首先,这是 Importing。通常它可能来自文件,这里我们使用三引号字符串语法:

>>> 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']

最后,将每个条目分成一个包含名字,姓氏,电话 Numbers 和地址的列表。我们使用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']]

:?模式与姓氏后的冒号匹配,因此它不会出现在结果列表中。使用_3 的maxsplit,我们可以将门牌 Numbers 与街道名称分开:

>>> [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. LiteralsMun

sub()用字符串或函数结果替换每次出现的模式。本示例演示使用带有函数sub()的“ munge”文本或随机化句子中每个单词中除第一个和最后一个字符外的所有字符的 Sequences:

>>> 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()匹配所有模式的出现,而不仅仅是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的实例而不是字符串。continue 前面的示例,如果作者希望在某些文本中找到所有副词及其位置,则可以按以下方式使用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")使正则表达式保持理智。如果没有它,则正则表达式中的每个反斜杠('\')都必须加上另一个前缀,以使其转义。例如,以下两行代码在Function上相同:

>>> re.match(r"\W(.)\1\W", " ff ")
<_sre.SRE_Match object at ...>
>>> re.match("\\W(.)\\1\\W", " ff ")
<_sre.SRE_Match object at ...>

当要匹配 Literals 反斜杠时,必须在正则表达式中将其转义。如果使用原始字符串符号,则表示r"\\"。如果没有原始字符串符号,则必须使用"\\\\",从而使以下代码行在Function上相同:

>>> re.match(r"\\", r"\\")
<_sre.SRE_Match object at ...>
>>> re.match("\\\\", r"\\")
<_sre.SRE_Match object at ...>