首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

re

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

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

解决方案是将Python的原始字符串表示法用于正则表达式模式; 在以'r'为前缀的字符串文字中不以任何特殊方式处理反斜杠。 所以r“\ n”是包含'\'和'n'的两个字符的字符串,而“\ n”是包含换行符的单字符字符串。 通常,模式将使用此原始字符串表示法以Python代码表示。

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

扩展内容

第三方正则表达式模块具有与标准库re模块兼容的API ,但提供了额外的功能和更全面的Unicode支持。

1.正则表达式语法

正则表达式(或RE)指定一组与之匹配的字符串; 这个模块中的函数可以让你检查一个特定的字符串是否与给定的正则表达式匹配(或者一个给定的正则表达式是否匹配一个特定的字符串,这个字符串可以归结为同一个东西)

正则表达式可以连接起来形成新的正则表达式; 如果AB都是正则表达式,那么AB也是一个正则表达式。通常,如果一个字符串p匹配A而另一个字符串q匹配B,则字符串pq将匹配AB。除非AB包含低优先级操作; AB之间边界条件; 或者有编号的组参考。因此,复杂的表达式可以很容易地从简单的基本表达式构建,就像这里描述的那样。有关正则表达式的理论和实现的详细信息,请参阅上面引用的Friedl书或几乎所有关于编译器构造的教科书。

正则表达式格式的简要说明如下。有关更多信息和更温和的演示,请参阅正则表达式HOWTO

正则表达式可以包含特殊字符和普通字符。 大多数普通字符,如'A','a'或'0'是最简单的正则表达式; 他们只是匹配自己。 您可以连接普通字符,因此最后匹配字符串'last'。 (在本节的其余部分中,我们将以这种特殊风格编写RE,通常不带引号,而字符串要用'单引号'来匹配)。

一些字符,如'|' 或'(')是特殊的,特殊字符或者代表普通字符类,或者影响它们周围正则表达式的解释方式正则表达式模式字符串不能包含空字节,但可以使用\数字符号指定空字节 ,例如'\ x00'。

重复限定符(*,+,?,{m,n}等)不能直接嵌套。 这避免了非贪心修饰符后缀?以及其他修饰符在其他实现中的歧义。 要将第二次重复应用于内部重复,可以使用括号。 例如,表达式(?:a {6})*匹配六个'a'字符的任意倍数。

特殊字符是:

'.'(Dot)在默认模式下,它匹配除换行符以外的任何字符。如果已经指定了DOTALL标志,它将匹配包括换行符在内的任何字符'^'(插入符)匹配字符串的开始,并且在MULTILINE模式下也会在每一个换行符后立即匹配'$'匹配字符串的末尾或者在字符串末尾的换行符之前,并且在MULTILINE模式下也与换行符匹配。 foo匹配'foo'和'foobar',而正则表达式foo $只匹配'foo'。更有趣的是,在'foo1 \ nfoo2 \ n'中搜索foo。$通常与'foo2'匹配,而在MULTILINE模式下搜索'foo1'在'foo \ n'中搜索单个$将会找到两个(空)匹配:一个在换行符之前,另一个在字符串末尾。'*'使得结果RE匹配前面的0个或更多个重复RE,尽可能多的重复。 ab *将匹配'a','ab'或'a',后跟任意数量的'b's'。'+'使得生成的RE匹配前面RE的一个或多个重复。 ab +将与'a'匹配,后跟任何非零数字的'b';它不会仅仅匹配'a'。'?'导致产生的RE匹配前面RE的0或1个重复。 AB?将匹配'a'或'ab'。*?,+ ?, ??'*','+'和'?'限定符都是贪婪的;它们匹配尽可能多的文本。有时候这种行为是不希望的;如果RE <。*>与<a> b <c>匹配,它将匹配整个字符串,而不仅仅是<a>。添加?在限定符之后以非贪婪或最小方式进行匹配;尽可能少的字符将被匹配。使用RE <。*?>将只匹配<a>。{m}指定刚才m个副本应匹配;更少的匹配导致整个RE不匹配。

例如,一个{6}将恰好匹配六个'a'字符,但不是五个。{m,n}使得到的RE从m到n匹配前一个RE,重复尽可能多的匹配。例如,{3,5}将匹配3到5个'a'字符。省略m指定零的下限,省略n指定无限上限。例如,{4,} b会匹配aaaab或数千个'a'字符,后跟b,但不匹配aaab。逗号可能不会被忽略,或者修饰符会与之前描述的形式混淆。{m,n}?使得结果RE从m到n重复前面的RE,试图尽可能少地重复匹配。这是以前限定符的非贪婪版本。例如,在6个字符的字符串'aaaaaa'上,{3,5}将匹配5个'a'字符,而{3,5}?只会匹配3个字符。'\'

要么逃避特殊字符(允许您匹配像'*''?'等等字符),要么发送特殊序列; 下面讨论特殊的序列。

如果您没有使用原始字符串来表示模式,请记住Python也使用反斜杠作为字符串文本中的转义序列; 如果转义序列不被Python的解析器识别,则反斜杠和后续字符将包含在结果字符串中。但是,如果Python能够识别结果序列,则反斜杠应重复两次。这很复杂,也很难理解,所以强烈建议您使用原始字符串,除了最简单的表达式。

[]

用于指示一组字符。在一组中:

  • 字符可以单独列上去,如[amk]将匹配'a''m''k'
  • 字符的范围可以通过给两个字符,并通过把它们分开来表示'-',例如[a-z]将匹配任何小写ASCII字母,[0-5][0-9]将所有的后两位数字从匹配0059,并[0-9A-Fa-f]会匹配任何十六进制数字。如果-被转义(例如[a\-z])或者被放置为第一个或最后一个字符(例如[a-]),它将与文字匹配'-'
  • 特殊字符在集合内部失去其特殊含义。例如,[(+*)]将匹配任何文字字符的'(''+''*',或')'
  • 诸如\w\S(定义如下)的字符类也被接受在一个集合内,尽管它们匹配的字符取决于是否LOCALEUNICODE模式有效。
  • 不在一个范围内的字符可以通过对该集合进行补充来匹配。如果该集合的第一个字符是'^',所有不在集合中的字符将被匹配。例如,[^5]将匹配除任何字符'5'[^^]并将匹配除任何字符'^'^如果它不是集合中的第一个字符,那么它没有特别的意义。
  • 要匹配']'集合内的文字,在其前面加上反斜线,或将其放在集合的开头。例如,无论是[()[\]{}][]()[{}]都将匹配一个括号。

'|'A|B,其中A和B可以是任意RE,创建一个匹配A或B的正则表达式'|'。以这种方式可以将任意数量的RE分开。这可以在组内使用(见下文)。当目标字符串被扫描时,'|'由左向右尝试分隔的RE 。当一个模式完全匹配时,该分支被接受。这意味着一旦A匹配,B就不会进一步测试,即使它会产生更长的整体匹配。换句话说,'|'操作员从不贪婪。为了匹配文字'|',使用\|或将其包含在字符类中,如in [|](...)匹配括号内的任何正则表达式,并指示组的开始和结束; 一个组的内容可以在匹配完成后被检索到,并且可以在后面的字符串中与\number特殊序列匹配,如下所述。要匹配的文字'('')'使用\(\),或将它们括字符类中:[(] [)](?...)这是一个扩展符号('?'后面的a '('不是有意义的)。'?'确定构造的含义和进一步语法之后的第一个字符是。扩展通常不会创建新的组; (?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>...)

类似于普通括号,但该组匹配的子字符串是通过符号组名称访问的名称。组名称必须是有效的Python标识符,并且每个组名称只能在正则表达式中定义一次。一个符号组也是一个编号组,就好像该组没有被命名一样。

命名组可以在三种情况下被引用。如果模式是(?P<quote>['"]).*?(?P=quote)(即匹配用单引号或双引号引用的字符串):

参考组“引用”的上下文

方法来引用它

在相同的模式本身

(?P =报价)(如图所示)\ 1

处理匹配对象m时

m.group('quote')m.end('quote')(等)

在传递给re.sub()的repl参数的字符串中,

\ g <quote> \ g <1> \ 1

  • (?P=quote) (如图所示)
  • \1
代码语言:txt
复制
when processing match object `m`   
  • m.group('quote')
  • m.end('quote') (etc.)
代码语言:txt
复制
in a string passed to the `repl` argument of `re.sub()`   
  • \g<quote>
  • \g<1>
  • \1

(?P = name)对指定组的反向引用; 它匹配与之前的名为name的组匹配的任何文本。(?#...)注释; (?= ...)匹配if ...匹配next,但不消耗任何字符串。 这被称为前瞻断言。 例如,Isaac(?= Asimov)只有跟着'Asimov'才会匹配'Isaac'。(?!...)匹配如果...与下一个匹配。 这是一个负面的前瞻断言。 例如,Isaac(?!Asimov)只有在没有跟随'Asimov'时才会匹配'Isaac'。(?<= ...)

如果字符串中的当前位置在当前位置...处结束匹配,则匹配。这被称为positive lookbehind assertion(?<=abc)def会找到一个匹配abcdef,因为lookbehind会备份3个字符并检查包含的模式是否匹配。所包含的模式必须只匹配一些固定长度的串,这意味着abc或者a|b是允许的,但a*a{3,4}不是。即使它们匹配某些固定长度的字符串,也不支持组引用。请注意,以正向lookbehind断言开始的模式在搜索字符串的开头不匹配; 你很可能会想使用这个search()函数而不是match()函数:

代码语言:javascript
复制
>>> import re
>>> m = re.search('(?<=abc)def', 'abcdef')
>>> m.group(0)
'def'

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

代码语言:javascript
复制
>>> m = re.search('(?<=-)\w+', 'spam-egg')
>>> m.group(0)
'egg'

(?<!...)如果字符串中的当前位置前面没有匹配...,则匹配。这称为negative lookbehind assertion.。 与正向lookbehind断言类似,所包含的模式只能匹配某些固定长度的字符串,并且不应包含组引用。 (?(id / name)yes-pattern | no-pattern)以负向lookbehind断言开始的模式可以匹配在搜索字符串的开头。

如果存在具有给定ID名称的组,则尝试匹配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个组中的一个。如果第一个数字是0,或为3个八进制数字长,也不会被解释为一组匹配,但与八进制值的字符。在字符类'['']'字符类中,所有数字转义都被视为字符。\A只匹配字符串的开头。\b匹配空字符串,但仅限于单词的开头或结尾。一个单词被定义为一个字母数字或下划线字符序列,因此单词的末尾用空格或非字母数字,非下划线字符表示。请注意,形式上,\b被定义为a \w\W字符之间的界限(反之亦然),或者在\w字符串的开始/结束之间,所以被认为是字母数字的精确字符集取决于UNICODELOCALE标志的值。例如,r'\bfoo\b'相匹配'foo''foo.''(foo)''bar foo baz'但不'foobar'还是'foo3'。在字符范围内,\b表示退格字符,以便与Python的字符串文字兼容。\B匹配空字符串,但仅限于它不在单词的开头或结尾。这意味着,r'py\B'比赛'python''py3''py2',而不是'py''py.''py!'\B是与\b相反,所以也受到的设置LOCALEUNICODE\d当该UNICODE标志未被指定时,匹配任何十进制数字; 这相当于一套[0-9]。使用UNICODE,它将匹配任何在Unicode字符属性数据库中被分类为十进制数字的内容。\DUNICODE未指定标志,匹配任何非数字字符; 这相当于一套[^0-9]。同UNICODE,它将匹配Unicode字符属性数据库中标记为数字的字符以外的任何内容。\s当该UNICODE标志没有被指定时,它匹配任何空格字符,这相当于该集合[ \t\n\r\f\v]。该LOCALE标志对空间的匹配没有额外的影响。如果UNICODE已设置,则会匹配字符[ \t\n\r\f\v]以及Unicode字符属性数据库中分类为空格的任何字符。\SUNICODE未指定标志,匹配任何非空白字符; 这相当于设定[^ \t\n\r\f\v]LOCALE标志对非空格比赛没有额外的效果。如果UNICODE已设置,则未匹配Unicode字符属性数据库中未标记为空格的任何字符。\wLOCALEUNICODE标志未指定,匹配任何字母数字字符和下划线; 这相当于一套[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字符串文字支持的标准转义符也被正则表达式解析器接受:

代码语言:javascript
复制
\a      \b      \f      \n
\r      \t      \v      \x
\\

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

八进制转义包含在一个有限的形式中:如果第一个数字是0,或者如果有三个八进制数字,则它被认为是八进制转义。否则,它是一个组参考。至于字符串文字,八进制转义字符的长度总是最多三位数字。

扩展内容

掌握正则表达式由O'Reilly出版的由Jeffrey Friedl撰写的关于正则表达式的书。本书的第二版不再涵盖Python,但第一版涵盖了编写良好正则表达式模式的细节。

2.模块内容

该模块定义了几个函数,常量和一个异常。一些函数是编译正则表达式的全功能方法的简化版本。大多数不平凡的应用程序总是使用编译后的表格。

re.compile(pattern, flags=0)

将正则表达式模式编译到正则表达式对象中,该对象可用于使用其match()search()方法进行匹配,如下所述。

表达式的行为可以通过指定一个标志值来修改。值可以是以下任何变量,使用按位或(|操作符)组合。

序列

代码语言:javascript
复制
prog = re.compile(pattern)
result = prog.match(string)

相当于

代码语言:javascript
复制
result = re.match(pattern, string)

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

注意

传递到最近模式的编译版本re.match()re.search()或者re.compile()是在同一时间只能使用几个正则表达式缓存,所以程序不必担心编译正则表达式。

re.DEBUG

显示关于编译表达式的调试信息

re.Ire.IGNORECASE

执行不区分大小写的匹配; 表达式[A-Z]也会匹配小写字母。这不受当前语言环境的影响。

re.Lre.LOCALE

\w\W\b\B\s以及\S依赖于当前的语言环境。

re.Mre.MULTILINE

指定时,模式字符'^'匹配字符串的开头和每行的开头(紧跟在每个换行符后面); 并且模式字符'$'匹配字符串的末尾和每行末尾(紧接在每个换行符之前)。默认情况下,'^'只匹配字符串的开始位置,并且'$'只匹配字符串的末尾和匹配字符串末尾的换行符(如果有)。

re.Sre.DOTALL

使'.'特殊字符匹配任何字符,包括换行符; 没有这个标志,'.'将会匹配换行符之外的任何内容。

re.Ure.UNICODE

\w\W\b\B\d\D\s\S依赖于Unicode字符属性数据库。

2.0版本中的新功能。

re.Xre.VERBOSE

该标志允许您编写正则表达式,通过允许您在视觉上分离模式的逻辑部分并添加注释,该正则表达式看起来更好,并且更易读。除非在字符类中或前面加上了未转义的反斜杠,否则模式内的空格将被忽略。当一行包含一个#不在字符类中并且没有非转义反斜杠#的行时,最左边的所有字符都将被忽略。

这意味着匹配一个十进制数的下面两个正则表达式对象在功能上是相等的:

代码语言:javascript
复制
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)

扫描字符串 查找正则表达式模式 产生匹配的第一个位置,并返回相应的MatchObject实例。None如果字符串中没有位置与模式匹配,则返回; 请注意,这与在字符串中的某处找到零长度匹配不同。

re.match(pattern, string, flags=0)

如果字符串开头的零个或多个字符与正则表达式模式匹配,则返回相应的MatchObject实例。如果字符串与模式不匹配,则返回None。请注意,这与零长度匹配不同。

请注意,即使在MULTILINE模式下,re.match()只会匹配字符串的开头,而不是每行的开头。

如果您想在字符串中的任何位置找到匹配项,请改用search()(另请参阅search()与match())。

re.split(pattern, string, maxsplit=0, flags=0)

根据模式的出现拆分字符串。如果在模式中使用捕获括号,则模式中所有组的文本也会作为结果列表的一部分返回。如果maxsplit不为零,则最多发生maxsplit分割,并且字符串的其余部分作为列表的最后一个元素返回。(不兼容性注释:在原始的Python 1.5版本中,maxsplit被忽略了,这在以后的版本中已经修复。)

代码语言:javascript
复制
>>> 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']

如果分隔符中有捕获组,并且它在字符串的起始处匹配,则结果将以空字符串开头。字符串的结尾也是一样:

代码语言:javascript
复制
>>> re.split('(\W+)', '...words, words...')
['', '...', 'words', ', ', 'words', '...', '']

这样,分隔符组件总是在结果列表中的相同索引处找到(例如,如果分隔符中有一个捕获组,第0个,第2个等等)。

请注意,split 将永远不会在空模式匹配上分割字符串。例如:

代码语言:javascript
复制
>>> re.split('x*', 'foo')
['foo']
>>> re.split("(?m)^$", "foo\n\nbar\n")
['foo\n\nbar\n']

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

re.findall(pattern, string, flags=0)

返回的所有非重叠的匹配模式 字符串,如字符串列表。该字符串进行扫描左到右,并匹配以发现的顺序返回。如果模式中存在一个或多个组,请返回组列表; 如果模式有多个组,这将是一个元组列表。空结果包含在结果中,除非他们触及另一场比赛的开始。

1.5.2版本的新功能。

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

re.finditer(pattern, string, flags=0)

返回一个迭代产生MatchObject过度的RE所有非重叠的匹配的实例图案的字符串。该字符串进行扫描左到右,并匹配以发现的顺序返回。空结果包含在结果中,除非他们触及另一场比赛的开始。

2.2版本中的新功能。

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

re.sub(pattern, repl, string, count=0, flags=0)

通过用替换repl替换字符串中最左边不重叠出现的模式而获得的字符串。 如果未找到该模式,则字符串将保持不变。 repl可以是一个字符串或一个函数; 如果它是一个字符串,则处理其中的任何反斜杠转义。 也就是\ n被转换为单个换行符,\ r被转换为回车符,等等。 像\ j这样的未知转义字符将被单独保留。 反向引用(例如\ 6)被替换为模式中由组6匹配的子字符串。 例如:

代码语言:javascript
复制
>>> 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 是一个函数,那么它被称为每个非重叠模式的发生。该函数采用单个匹配对象参数,并返回替换字符串。例如:

代码语言:javascript
复制
>>> 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-'

在string-type repl参数中,除了上述的字符转义和反向引用外,\ g <name>将使用由(?P <name> ...)语法定义的名为name的组匹配的子字符串。 \ g <号码>使用相应的组号码; \ g 2因此等于\ 2,但在诸如\ g <2>的替换中不是不明确的。 \ 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(string)

返回所有非字母数字字符串的字符串 ; 如果你想匹配一个可能有正则表达式元字符的任意文字字符串,这很有用。

re.purge()

清除正则表达式缓存。

exception re.error

当传递给其中一个函数的字符串不是有效的正则表达式(例如,它可能包含不匹配的圆括号)或编译或匹配过程中发生其他错误时引发的异常。如果一个字符串不包含匹配的模式,那永远不会出错。

3.正则表达式对象

class re.RegexObject

RegexObject类支持下列方法和属性:

search(string[, pos[, endpos]])

扫描字符串查找此正则表达式产生匹配的位置,并返回相应的MatchObject实例。 如果字符串中没有位置与模式匹配,则返回None; 请注意,这与在字符串中的某处找到零长度匹配不同。

可选的第二个参数pos在搜索要开始的字符串中给出一个索引; 它默认为0。这不完全等同于切分字符串; 该'^'模式字符在字符串的真正开始,并在仅仅一个换行符后的位置相匹配,但不一定,其中搜索是启动索引。

可选参数endpos限制字符串搜索的距离; 它就好像字符串是endpos字符一样长,所以只有从pos到的字符endpos - 1才会被搜索到匹配。如果endpos小于pos,则不会找到匹配,否则,如果rx是已编译的正则表达式对象,rx.search(string, 0, 50)则等同于rx.search(string[:50], 0)

代码语言:javascript
复制
>>> 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]])

如果字符串开头的零个或多个字符与此正则表达式匹配,则返回相应的实例。如果字符串与模式不匹配,则返回; 请注意,这与零长度匹配不同。MatchObjectNone

The optional pos and endpos parameters have the same meaning as for the search() method.

代码语言:javascript
复制
>>> 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 ...>

如果您想在字符串中的任何位置找到匹配项,请改用search()(另请参阅search()与match())。

split(string, maxsplit=0)

split()使用编译模式的函数相同。

findall(string[, pos[, endpos]])

findall()函数类似,使用编译模式,但也接受限制搜索区域的可选posendpos参数match()

finditer(string[, pos[, endpos]])

finditer()函数类似,使用编译模式,但也接受限制搜索区域的可选posendpos参数match()

sub(repl, string, count=0)

sub()使用编译模式的函数相同。

subn(repl, string, count=0)

subn()使用编译模式的函数相同。

flags

正则表达式匹配标志。这是模式中给出的标志compile()和任何(?...)内联标志的组合。

groups

模式中的捕获组数量。

groupindex

一个字典,用于映射由(?P<id>)组号定义的任何符号组名。如果模式中没有使用符号组,则字典为空。

pattern

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

4.匹配对象

class re.MatchObject

匹配对象始终具有布尔值True。 由于match()和search()在不匹配时返回None,因此可以测试是否与简单的if语句匹配:

代码语言:javascript
复制
match = re.search(pattern, string)
if match:
    process(match)

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

expand(template)

返回通过在模板字符串模板上执行反斜杠替换而获得的字符串,如sub()方法所做的那样。 \ n等转义被转换为适当的字符,并且数字反向引用(\ 1,\ 2)和命名反向引用(\ g <1>,\ g <name>)被替换为相应组的内容。

group([group1, ...])

返回匹配的一个或多个子组。 如果有一个参数,结果是一个单一的字符串; 如果有多个参数,则结果是每个参数有一个项目的元组。 没有参数,group1默认为零(整个匹配被返回)。 如果groupN参数为零,则相应的返回值是整个匹配的字符串; 如果它在1..99的包含范围内,则它是与相应的括号内的组匹配的字符串。 如果组编号为负数或大于模式中定义的组数,则会引发IndexError异常。 如果一个组包含在不匹配的模式的一部分中,则相应的结果为无。 如果一个组包含在多次匹配的模式的一部分中,则返回最后的匹配。

代码语言:javascript
复制
>>> 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异常。

一个中等复杂的例子:

代码语言:javascript
复制
>>> m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "Malcolm Reynolds")
>>> m.group('first_name')
'Malcolm'
>>> m.group('last_name')
'Reynolds'

命名组也可以通过它们的索引来引用:

代码语言:javascript
复制
>>> m.group(1)
'Malcolm'
>>> m.group(2)
'Reynolds'

如果一个组匹配多次,只能访问最后一场比赛:

代码语言:javascript
复制
>>> m = re.match(r"(..)+", "a1b2c3")  # Matches 3 times.
>>> m.group(1)                        # Returns only the last match.
'c3'

groups([default])

返回一个包含匹配所有子组的元组,从1开始,直到模式中有多个组。该默认参数用于那些没有参加比赛组; 它默认为None。(不兼容性注释:在原始的Python 1.5版本中,如果元组长度是一个元素,则会返回一个字符串,而在后来的版本中(从1.5.1开始),这种情况下会返回一个单例元组。

例如:

代码语言:javascript
复制
>>> m = re.match(r"(\d+)\.(\d+)", "24.1632")
>>> m.groups()
('24', '1632')

如果我们将小数点后的所有数字都设为可选,则并非所有组都可以参与比赛。 除非给出默认参数,否则这些组将默认为None。

代码语言:javascript
复制
>>> 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])

返回包含匹配的所有命名子组的字典的子集名称。 缺省参数用于未参与匹配的组; 它默认为None。 例如:

代码语言:javascript
复制
>>> 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])

返回按组匹配的子串的开始和结束索引; 组默认为零(意味着整个匹配的子字符串)。 如果组存在,则返回-1,但不参与匹配。 对于一个匹配对象m和一个对匹配有贡献的组g,与组g匹配的子串(相当于m.group(g))是

代码语言:javascript
复制
m.string[m.start(g):m.end(g)]

请注意,如果组匹配空字符串,则m.start(组)将等于m.end(组)。 例如,在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的示例:

代码语言:javascript
复制
>>> email = "tony@tiremove_thisger.net"
>>> m = re.search("remove_this", email)
>>> email[:m.start()] + email[m.end():]
'tony@tiger.net'

span([group])

对于MatchObject m,返回2元组(m.start(group), m.end(group))。请注意,如果没有对匹配做出贡献,则是(-1, -1)组 在匹配中默认为零。

pos

传递给或的方法的pos的值。这是RE引擎开始寻找匹配的字符串的索引。search()match()RegexObject

endpos

传递给RegexObject的search()或match()方法的endpos的值。 这是RE引擎不会去的字符串的索引。

lastindex

最后一个匹配捕获组的整数索引,或者如果没有匹配组,则为None。 例如,如果将表达式(a)b,((a)(b))和((ab))应用于字符串“ab”,则lastindex == 1,而表达式(a)(b)将 如果应用于相同的字符串,则lastindex == 2。

lastgroup

最后匹配的捕获组的名称,如果组没有名称,或者根本没有匹配组,则为None。

re

match()或search()方法生成此MatchObject实例的正则表达式对象。

string

传递给match()或search()的字符串。

5.例子

5.1 检查一对

在这个例子中,我们将使用以下辅助函数来更加优雅地显示匹配对象:

代码语言:javascript
复制
def displaymatch(match):
    if match is None:
        return None
    return '<Match: %r, groups=%r>' % (match.group(), match.groups())

假设您正在编写一个扑克程序,其中玩家的手表示为5个字符的字符串,每个字符代表一张牌,“a”代表王牌,“k”代表国王,“q”代表女王,“j”代表jack, “t”为10,“2”至“9”代表具有该值的卡。

要查看给定的字符串是否是有效的手,可以执行以下操作:

代码语言:javascript
复制
>>> 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"包含一对,或两个相同的价值卡。为了与正则表达式匹配,可以使用反向引用:

代码语言:javascript
复制
>>> 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()方法:

代码语言:javascript
复制
>>> 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'

5.2 模拟scanf()

Python目前不具有与scanf()等效的功能。 正则表达式通常比scanf()格式的字符串更强大,但也更加冗长。 下表提供了一些或多或少的scanf()格式标记和正则表达式之间的等价映射。

scanf()令牌

正则表达式

%C

.

%5c

.{5}

%d

- + \ d +

%e,%E,%f,%g

? - +(?\ d +(\ d *)| \ d +)(EE \ d +?)?

%i

? - +(0XX + | 00-7 * | \ d +)

%o

-+?0-7+

%s

\ S +

%u

\ d +

%x,%X

- +(0XX)\ DA -Fa-f +?

从字符串中提取文件名和数字

代码语言:javascript
复制
/usr/sbin/sendmail - 0 errors, 4 warnings

你会使用与scanf()类似的格式

代码语言:javascript
复制
%s - %d errors, %d warnings

等效的正则表达式是

代码语言:javascript
复制
(\S+) - (\d+) errors, (\d+) warnings

5.3 search()与match()

Python提供了基于正则表达式的两种不同的原始操作:re.match()仅在字符串的开始处检查匹配,而re.search()检查字符串中任意位置的匹配(这是Perl默认执行的操作)。

例如:

代码语言:javascript
复制
>>> re.match("c", "abcdef")    # No match
>>> re.search("c", "abcdef")   # Match
<_sre.SRE_Match object at ...>

以'^'开头的正则表达式可以与search()一起用于限制字符串开始处的匹配:

代码语言:javascript
复制
>>> 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()与以'^'开头的正则表达式匹配每行的开头。

代码语言:javascript
复制
>>> re.match('X', 'A\nB\nX', re.MULTILINE)  # No match
>>> re.search('^X', 'A\nB\nX', re.MULTILINE)  # Match
<_sre.SRE_Match object at ...>

5.4 制作电话簿

split()将字符串分割成由传递模式分隔的列表。该方法对于将文本数据转换为可由Python轻松读取和修改的数据结构非常有用,如以下创建电话簿的示例所示。

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

代码语言:javascript
复制
>>> 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"""

条目由一个或多个换行符分隔。现在我们将字符串转换为一个列表,每个非空行都有自己的条目:

代码语言:javascript
复制
>>> 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参数,因为地址中有空格,我们的分割模式,在其中为:

代码语言:javascript
复制
>>> [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']]

:? 模式匹配姓氏后的冒号,以便它不会出现在结果列表中。 我们可以将最多的房屋号码与街道名称分开:

代码语言:javascript
复制
>>> [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']]

5.5 文本Munging

sub()用一个字符串或一个函数的结果替换每个模式的出现。 这个例子演示了如何使用sub()和函数来“闯入”文本,或者随机化除了第一个和最后一个字符之外的每个单词中所有字符的顺序:

代码语言:javascript
复制
>>> 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.'

5.6 找到所有副词

findall()匹配所有出现的模式,而不仅仅是search()所做的第一个。 例如,如果一个人是作家,并且想要在某些文本中找到所有副词,他或她可以按以下方式使用findall():

代码语言:javascript
复制
>>> text = "He was carefully disguised but captured quickly by police."
>>> re.findall(r"\w+ly", text)
['carefully', 'quickly']

5.7 找到所有副词及其位置

如果需要关于匹配文本的所有模式匹配的更多信息,finditer()是有用的,因为它提供了MatchObject的实例而不是字符串。 继续前面的例子,如果一个作家想要在某些文本中找到所有副词及其位置,他或她会按以下方式使用finditer():

代码语言:javascript
复制
>>> 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

5.8 原始字符串符号

原始字符串符号(r“text”)使正则表达式保持正常。 没有它,正则表达式中的每个反斜杠('\')必须以另一个反斜杠作为前缀。 例如,以下两行代码在功能上是相同的:

代码语言:javascript
复制
>>> re.match(r"\W(.)\1\W", " ff ")
<_sre.SRE_Match object at ...>
>>> re.match("\\W(.)\\1\\W", " ff ")
<_sre.SRE_Match object at ...>

当想要匹配文字反斜杠时,它必须在正则表达式中转义。用原始字符串表示法,这意味着r"\\"。没有原始字符串表示法,必须使用"\\\\",使以下代码行功能相同:

代码语言:javascript
复制
>>> re.match(r"\\", r"\\")
<_sre.SRE_Match object at ...>
>>> re.match("\\\\", r"\\")
<_sre.SRE_Match object at ...>

扫码关注腾讯云开发者

领取腾讯云代金券