元字符(Meta Characters)是正则表达式中具有特殊意义的专用字符,在Python中也不例外,是用来指明前导字符(位于元字符前的字符)在目标对象中的出现模式。
在正则表达式中,方括号 ( [] ) 中指定的一组字符组成一个字符类。
# 元字符序列匹配类中的任何单个字符 >>> s = 'foo123bar' # 3个任意连续字符匹配 >>> re.search('[0-9][0-9][0-9]', s) <_sre.SRE_Match object; span=(3, 6), match='123'> >>> re.search('[0-9][0-9][0-9]', 'foo456bar') <_sre.SRE_Match object; span=(3, 6), match='456'> >>> re.search('[0-9][0-9][0-9]', '234baz') <_sre.SRE_Match object; span=(0, 3), match='234'> >>> re.search('[0-9][0-9][0-9]', 'qux678') <_sre.SRE_Match object; span=(3, 6), match='678'> # 匹配不上的情况 >>> print(re.search('[0-9][0-9][0-9]', '12foo34')) None
通配符点 ( . ) 元字符匹配除换行符以外的任何字符。
>>> s = 'foo123bar' >>> re.search('1.3', s) <_sre.SRE_Match object; span=(3, 6), match='123'> >>> s = 'foo13bar' >>> print(re.search('1.3', s)) None
re模块支持的元字符
下面列表都是元字符的描述,对元字符进行分类描述方便记忆。 这个要是看不懂直接看跳过看下面的例子。
指定要匹配的特定字符集。 字符类元字符序列将匹配该类中包含的任何单个字符。
# 元字符序列[artz]匹配任何单个'a'、'r'、't'或'z'字符 # ba[artz]同时匹配'bar'and 'baz'(也将匹配'baa'and 'bat')。 >>> re.search('ba[artz]', 'foobarqux') <_sre.SRE_Match object; span=(3, 6), match='bar'> >>> re.search('ba[artz]', 'foobazqux') <_sre.SRE_Match object; span=(3, 6), match='baz'>
匹配和[a-z]之间的任何小写字母字符。
>>> re.search('[a-z]', 'FOObar') <_sre.SRE_Match object; span=(3, 4), match='b'>
匹配和[0-9]之间任何数字字符。
>>> re.search('[0-9][0-9]', 'foo123bar') <_sre.SRE_Match object; span=(3, 5), match='12'>
[0-9a-fA-F]匹配任何十六进制数字字符。
>>> re.search('[0-9a-fA-f]', '--- a0 ---') <_sre.SRE_Match object; span=(4, 5), match='a'>
[^0-9]匹配任何不是数字的字符开头的字符。
>>> re.search('[^0-9]', '12345foo') <_sre.SRE_Match object; span=(5, 6), match='f'>
如果一个^字符出现在字符类中但不是第一个字符则无结果。
>>> re.search('[#:^]', 'foo^bar:baz#qux') <_sre.SRE_Match object; span=(3, 4), match='^'>
可以通过用连字符分隔字符来指定字符类中的字符范围,可以将其作为第一个或最后一个字符放置,或者使用反斜杠 ( \ ) 对其进行转义。
# 直接查找符号 >>> re.search('[-abc]', '123-456') <_sre.SRE_Match object; span=(3, 4), match='-'> >>> re.search('[abc-]', '123-456') <_sre.SRE_Match object; span=(3, 4), match='-'> >>> re.search('[ab\-c]', '123-456') <_sre.SRE_Match object; span=(3, 4), match='-'> # 查找转义符号 >>> re.search('[]]', 'foo[1]') <_sre.SRE_Match object; span=(5, 6), match=']'> >>> re.search('[ab\]cd]', 'foo[1]') <_sre.SRE_Match object; span=(5, 6), match=']'> # [ ] 内的元字符失去意义转义成字符处理 >>> re.search('[)*+|]', '123*456') <_sre.SRE_Match object; span=(3, 4), match='*'> >>> re.search('[)*+|]', '123+456') <_sre.SRE_Match object; span=(3, 4), match='+'>点 ( . ) 通配符
匹配除换行符以外的任何单个字符。
>>> re.search('foo.bar', 'fooxbar') <_sre.SRE_Match object; span=(0, 7), match='fooxbar'> >>> print(re.search('foo.bar', 'foobar')) None >>> print(re.search('foo.bar', 'foo\nbar')) None >>> print(re.search('foo.bar', 'foosbar')) <_sre.SRE_Match object; span=(0, 7), match='foosbar'>\w 和 \W 单词字符匹配
\w匹配任何字母数字字符,单词字符是大写和小写字母、数字和下划线 ( _) 字符。
\w 等于 [a-zA-Z0-9_] 。
>>> re.search('\w', '#(.a$@&') <_sre.SRE_Match object; span=(3, 4), match='a'> >>> re.search('[a-zA-Z0-9_]', '#(.a$@&') <_sre.SRE_Match object; span=(3, 4), match='a'>
\W是相反的。它匹配任何非单词字符。
\W 等于 [^a-zA-Z0-9_] 。
>>> re.search('\W', 'a_1*3Qb') <_sre.SRE_Match object; span=(3, 4), match='*'> >>> re.search('[^a-zA-Z0-9_]', 'a_1*3Qb') <_sre.SRE_Match object; span=(3, 4), match='*'>\d 和 \D 字符十进制数字匹配
\d匹配任何十进制数字字符,等价于[0-9]。
>>> re.search('\d', 'abc4def') <_sre.SRE_Match object; span=(3, 4), match='4'>
\D匹配任何不是十进制数字的字符,等价于[^0-9]。
>>> re.search('\D', '234Q678') <_sre.SRE_Match object; span=(3, 4), match='Q'>\s 和 \S 字符空格匹配
\s匹配任何空白字符,同时也匹配换行符。
>>> re.search('\s', 'foo\nbar baz') <_sre.SRE_Match object; span=(3, 4), match='\n'>
\S匹配任何不是空格的字符。
>>> re.search('\S', ' \n foo \n ') <_sre.SRE_Match object; span=(4, 5), match='f'>混合使用 \w, \W, \d, \D, \s, 和\S
字符类序列\w, \W, \d, \D, \s, 和\S也可以出现在方括号字符类中。
# [\d\w\s]匹配任何数字、单词或空白字符 >>> re.search('[\d\w\s]', '---3---') <_sre.SRE_Match object; span=(3, 4), match='3'> >>> re.search('[\d\w\s]', '---a---') <_sre.SRE_Match object; span=(3, 4), match='a'> >>> re.search('[\d\w\s]', '--- ---') <_sre.SRE_Match object; span=(3, 4), match=' '> # 由于\w包含\d,相同的字符类也可以表示为略短[\w\s] >>> re.search('[\w\s]', '---a---') <_sre.SRE_Match object; span=(3, 4), match='a'> >>> re.search('[\w\s]', '---a---') <_sre.SRE_Match object; span=(3, 4), match='a'> >>> re.search('[\w\s]', '--- ---') <_sre.SRE_Match object; span=(3, 4), match=' '>类别2:转义元字符反斜杠 ( \ ) 转义元字符
反斜杠会删除元字符的特殊含义。
>>> re.search('.', 'foo.bar') <_sre.SRE_Match object; span=(0, 1), match='f'> >>> re.search('\.', 'foo.bar') # 非通配符 <_sre.SRE_Match object; span=(3, 4), match='.'> >>> re.search(r'\\', 'foo\bar') <_sre.SRE_Match object; span=(3, 4), match='\\'>类别3:锚点
不匹配搜索字符串中的任何实际字符,并且在解析期间它们不使用任何搜索字符串。指示搜索字符串中必须发生匹配的特定位置。
^ 和 \A 字符串的开头匹配项
>>> re.search('^foo', 'foobar') <_sre.SRE_Match object; span=(0, 3), match='foo'> >>> print(re.search('^foo', 'barfoo')) None >>> re.search('\Afoo', 'foobar') <_sre.SRE_Match object; span=(0, 3), match='foo'> >>> print(re.search('\Afoo', 'barfoo')) None$ 和\Z 字符串的结尾匹配项
>>> re.search('bar$', 'foobar') <_sre.SRE_Match object; span=(3, 6), match='bar'> >>> print(re.search('bar$', 'barfoo')) None >>> re.search('bar\Z', 'foobar') <_sre.SRE_Match object; span=(3, 6), match='bar'> >>> print(re.search('bar\Z', 'barfoo')) None # 特殊$也在搜索字符串末尾的单个换行符之前匹配 >>> re.search('bar$', 'foobar\n') <_sre.SRE_Match object; span=(3, 6), match='bar'>\b 和 \B 单词匹配
\b 必须在单词的开头或结尾。
# 单词开头 >>> re.search(r'\bbar', 'foo bar') <_sre.SRE_Match object; span=(4, 7), match='bar'> >>> re.search(r'\bbar', 'foo.bar') <_sre.SRE_Match object; span=(4, 7), match='bar'> >>> print(re.search(r'\bbar', 'foobar')) None # 单词结尾 >>> re.search(r'foo\b', 'foo bar') <_sre.SRE_Match object; span=(0, 3), match='foo'> >>> re.search(r'foo\b', 'foo.bar') <_sre.SRE_Match object; span=(0, 3), match='foo'> >>> print(re.search(r'foo\b', 'foobar')) None # 单词居中 >>> re.search(r'\bbar\b', 'foo bar baz') <_sre.SRE_Match object; span=(4, 7), match='bar'> >>> re.search(r'\bbar\b', 'foo(bar)baz') <_sre.SRE_Match object; span=(4, 7), match='bar'> >>> print(re.search(r'\bbar\b', 'foobarbaz')) None
\B 不能在单词的开头或结尾。
>>> print(re.search(r'\Bfoo\B', 'foo')) None >>> print(re.search(r'\Bfoo\B', '.foo.')) None >>> re.search(r'\Bfoo\B', 'barfoobaz') <_sre.SRE_Match object; span=(3, 6), match='foo'>类别4:量词
该部分必须出现多少次才能使匹配成功。
* 匹配前面的子表达式零次或多次>>> re.search('foo-*bar', 'foobar') <_sre.SRE_Match object; span=(0, 6), match='foobar'> >>> re.search('foo-*bar', 'foo-bar') <_sre.SRE_Match object; span=(0, 7), match='foo-bar'> >>> re.search('foo-*bar', 'foo--bar') <_sre.SRE_Match object; span=(0, 8), match='foo--bar'>
匹配2个字符中全部的内容。
>>> re.search('foo.*bar', '# foo jklasajk#*(@ bar #') <_sre.SRE_Match object; span=(2, 22), match='foo jklasajk#*(@ bar'>+ 匹配前面的子表达式一次或多次
>>> print(re.search('foo-+bar', 'foobar')) None >>> re.search('foo-+bar', 'foo-bar') <_sre.SRE_Match object; span=(0, 7), match='foo-bar'> >>> re.search('foo-+bar', 'foo--bar') <_sre.SRE_Match object; span=(0, 8), match='foo--bar'>? 匹配前面的子表达式零次或一次
>>> re.search('foo-?bar', 'foobar') <_sre.SRE_Match object; span=(0, 6), match='foobar'> >>> re.search('foo-?bar', 'foo-bar') <_sre.SRE_Match object; span=(0, 7), match='foo-bar'> >>> print(re.search('foo-?bar', 'foo--bar')) None.*?、+?、?? 最小长度匹配
加问号则表示为最小长度匹配的懒惰模式。
### + 和 +? 代替了 * 和 *? # .*全匹配贪婪模式 >>> re.search('<.*>', '%<foo> <bar> <baz>%') <_sre.SRE_Match object; span=(1, 18), match='<foo> <bar> <baz>'> # *? 前一个字符0次或无限次扩展,最小匹配 >>> re.search('<.*?>', '%<foo> <bar> <baz>%') <_sre.SRE_Match object; span=(1, 6), match='<foo>'> # .+ 前一个字符1次或无限次扩展,最小匹配 >>> re.search('<.+>', '%<foo> <bar> <baz>%') <_sre.SRE_Match object; span=(1, 18), match='<foo> <bar> <baz>'> # .+? 前一个字符1次或无限次扩展,最小匹配 >>> re.search('<.+?>', '%<foo> <bar> <baz>%') <_sre.SRE_Match object; span=(1, 6), match='<foo>'> # ? 匹配懒惰模式 >>> re.search('ba?', 'baaaa') <_sre.SRE_Match object; span=(0, 2), match='ba'> # ?? 前一个字符0次或1次扩展,最小匹配 >>> re.search('ba??', 'baaaa') <_sre.SRE_Match object; span=(0, 1), match='b'>{m} 完全匹配m次前面元字符的正则表达式。
>>> print(re.search('x-{3}x', 'x--x')) None >>> re.search('x-{3}x', 'x---x') <_sre.SRE_Match object; span=(0, 5), match='x---x'> >>> print(re.search('x-{3}x', 'x----x')) None{m,n} 匹配前面正则表达式的任意数量的重复从m到n次
>>> for i in range(1, 6): ... s = f"x{'-' * i}x" ... print(f'{i} {s:10}', re.search('x-{2,4}x', s)) ... 1 x-x None 2 x--x <_sre.SRE_Match object; span=(0, 4), match='x--x'> 3 x---x <_sre.SRE_Match object; span=(0, 5), match='x---x'> 4 x----x <_sre.SRE_Match object; span=(0, 6), match='x----x'> 5 x-----x None
>>> re.search('x{}y', 'x{}y') <_sre.SRE_Match object; span=(0, 4), match='x{}y'> >>> re.search('x{foo}y', 'x{foo}y') <_sre.SRE_Match object; span=(0, 7), match='x{foo}y'> >>> re.search('x{a:b}y', 'x{a:b}y') <_sre.SRE_Match object; span=(0, 7), match='x{a:b}y'> >>> re.search('x{1,3,5}y', 'x{1,3,5}y') <_sre.SRE_Match object; span=(0, 9), match='x{1,3,5}y'> >>> re.search('x{foo,bar}y', 'x{foo,bar}y') <_sre.SRE_Match object; span=(0, 11), match='x{foo,bar}y'>{m,n}? 只匹配一次
非贪婪(懒惰)版本 {m,n}。
>>> re.search('a{3,5}', 'aaaaaaaa') <_sre.SRE_Match object; span=(0, 5), match='aaaaa'> >>> re.search('a{3,5}?', 'aaaaaaaa') <_sre.SRE_Match object; span=(0, 3), match='aaa'>类别5:分组构造和反向引用
分组构造将 Python 中的正则表达式分解为子表达式或组。
分组:一个组代表一个单一的句法实体。附加元字符作为一个单元应用于整个组。
捕获:一些分组结构还捕获与组中的子表达式匹配的搜索字符串部分。可以通过几种不同的机制检索捕获的匹配项。
(<regex>),定义子表达式或组。
# 括号中的正则表达式仅匹配括号的内容 >>> re.search('(bar)', 'foo bar baz') <_sre.SRE_Match object; span=(4, 7), match='bar'> >>> re.search('bar', 'foo bar baz') <_sre.SRE_Match object; span=(4, 7), match='bar'>将组视为一个单元
组后面的量词元字符对组中指定的整个子表达式作为一个单元进行操作。
# 元字符+仅适用于字符'r','ba'随后出现一次或多次'r'。 >>> re.search('bar+', 'foo bar baz') <_sre.SRE_Match object; span=(4, 7), match='bar'> >>> re.search('(bar)+', 'foo bar baz') <_sre.SRE_Match object; span=(4, 7), match='bar'> >>> re.search('(bar)+', 'foo barbar baz') <_sre.SRE_Match object; span=(4, 10), match='barbar'> >>> re.search('(bar)+', 'foo barbarbarbar baz') <_sre.SRE_Match object; span=(4, 16), match='barbarbarbar'>
返回一个元组,其中包含从正则表达式匹配中捕获的所有组。
>>> m = re.search('(\w+),(\w+),(\w+)', 'foo,quux,baz') >>> m <_sre.SRE_Match object; span=(0, 12), match='foo:quux:baz'> >>> m.groups() ('foo', 'quux', 'baz')捕获组,m.group(<n>)
返回包含<n>捕获的匹配项的字符串。
>>> m = re.search('(\w+),(\w+),(\w+)', 'foo,quux,baz') >>> m.groups() ('foo', 'quux', 'baz') >>> m.group(0) ('foo', 'quux', 'baz') >>> m.group(1) 'foo' >>> m.group(2) 'quux' >>> m.group(3) 'baz'捕获组,m.group(<n1>, <n2>, …)
返回一个包含指定捕获匹配序号的元组。
>>> m = re.search('(\w+),(\w+),(\w+)', 'foo,quux,baz') >>> m.groups() ('foo', 'quux', 'baz') >>> m.group(2, 3) ('quux', 'baz') >>> m.group(3, 2, 1) ('baz', 'quux', 'foo')类别6:反向引用\<num> 匹配连续相同字符
>>> regex = r'(\w+),\1' >>> m = re.search(regex, 'foo,foo') >>> m <_sre.SRE_Match object; span=(0, 7), match='foo,foo'> >>> m.group(1) 'foo' >>> m = re.search(regex, 'qux,qux') >>> m <_sre.SRE_Match object; span=(0, 7), match='qux,qux'> >>> m.group(1) 'qux' >>> m = re.search(regex, 'foo,qux') >>> print(m) None类别7:其他分组结构(?P<name><regex>) 创建捕获组并命名
>>> m = re.search('(?P<w1>\w+),(?P<w2>\w+),(?P<w3>\w+)', 'foo,quux,baz') >>> m.groups() ('foo', 'quux', 'baz') >>> m.group('w1') 'foo' >>> m.group('w3') 'baz' >>> m.group('w1', 'w2', 'w3') ('foo', 'quux', 'baz') >>> m.group(1, 2, 3) ('foo', 'quux', 'baz')(?P=<name>) 匹配先前捕获名的内容
>>> m = re.search(r'(\w+),\1', 'foo,foo') >>> m <_sre.SRE_Match object; span=(0, 7), match='foo,foo'> >>> m.group(1) 'foo' >>> m = re.search(r'(?P<word>\w+),(?P=word)', 'foo,foo') >>> m <_sre.SRE_Match object; span=(0, 7), match='foo,foo'> >>> m.group('word') 'foo'(?:<regex>) 创建一个非捕获组
>>> m = re.search('(\w+),(?:\w+),(\w+)', 'foo,quux,baz') >>> m.groups() ('foo', 'baz') >>> m.group(1) 'foo' >>> m.group(2) 'baz'指定条件匹配
(?(<n>)<yes-regex>|<no-regex>)
(?(<name>)<yes-regex>|<no-regex>)
# ^(###)?表示搜索字符串可选地以 . 开头'###'。如果是这样,那么周围的分组括号###将创建一个编号为的组1。否则,不会存在这样的组 # foo字面上匹配字符串'foo' # (?(1)bar|baz)匹配'bar'组是否1存在和'baz'不存在 regex = r'^(###)?foo(?(1)bar|baz)' # 搜索字符串'###foobar'确实以 开头'###',因此解析器创建了一个编号为 的组1。然后条件匹配是针对'bar'匹配的 >>> re.search(regex, '###foobar') <_sre.SRE_Match object; span=(0, 9), match='###foobar'> # 搜索字符串'###foobaz'确实以 开头'###',因此解析器创建了一个编号为 的组1。然后条件匹配是反对'bar',不匹配。 >>> print(re.search(regex, '###foobaz')) None # 搜索字符串'foobar'不以 开头'###',因此没有编号为 的组1。然后条件匹配是反对'baz',不匹配。 >>> print(re.search(regex, 'foobar')) None # 搜索字符串'foobaz'不以 开头'###',因此没有编号为 的组1。然后条件匹配是针对'baz'匹配的。 >>> re.search(regex, 'foobaz') <_sre.SRE_Match object; span=(0, 6), match='foobaz'>类别8:Lookahead 和 Lookbehind 断言
根据解析器在搜索字符串中当前位置的后面(左侧)或前面(右侧)来确定 Python 中正则表达式匹配的成功或失败。积极前瞻断言可表示为:(?=lookahead_regex)
(?=<lookahead_regex>) 积极前瞻断言# 断言正则表达式解析器当前位置之后的内容必须匹配 # 前瞻断言(?=[a-z])指定后面的'foo'必须是小写字母字符。 >>> re.search('foo(?=[a-z])', 'foobar') <_sre.SRE_Match object; span=(0, 3), match='foo'> # 前瞻失败的例子,foo的下一个字符是'1' >>> print(re.search('foo(?=[a-z])', 'foo123')) None # 前瞻的独特之处<lookahead_regex>在于不消耗搜索字符串中匹配的部分,并且它不是返回的匹配对象的一部分。 >>> re.search('foo(?=[a-z])', 'foobar') <_sre.SRE_Match object; span=(0, 3), match='foo'> # 举例对比观察,?=断言的区别 >>> m = re.search('foo(?=[a-z])(?P<ch>.)', 'foobar') >>> m.group('ch') 'b' >>> m = re.search('foo([a-z])(?P<ch>.)', 'foobar') >>> m.group('ch') 'a'(?!<lookahead_regex>) 否定的前瞻断言
# 例子和之前的前瞻积极断言相反 >>> re.search('foo(?=[a-z])', 'foobar') <_sre.SRE_Match object; span=(0, 3), match='foo'> >>> print(re.search('foo(?![a-z])', 'foobar')) None >>> print(re.search('foo(?=[a-z])', 'foo123')) None >>> re.search('foo(?![a-z])', 'foo123') <_sre.SRE_Match object; span=(0, 3), match='foo'>(?<=<lookbehind_regex>) 积极的后向断言
# 断言正则表达式解析器当前位置之前的内容匹配 # 断言指定'foo'必须先于'bar' >>> re.search('(?<=foo)bar', 'foobar') <_sre.SRE_Match object; span=(3, 6), match='bar'> >>> print(re.search('(?<=qux)bar', 'foobar')) None(?<!–<lookbehind_regex–>) 否定的向后断言
# 例子和之前的向后积极断言相反 >>> print(re.search('(?<!foo)bar', 'foobar')) None >>> re.search('(?<!qux)bar', 'foobar') <_sre.SRE_Match object; span=(3, 6), match='bar'>类别9:杂项元字符(?#…) 指定注释
# 正则表达式解析器忽略(?#...)序列中包含的任何内容 >>> re.search('bar(?#This is a comment) *baz', 'foo bar baz qux') <_sre.SRE_Match object; span=(4, 11), match='bar baz'>竖条或管道 ( | ) 指定要匹配的一组备选方案
# 形式的表达式最多匹配一个指定的表达式:<regex1>|<regex2>|...|<regexn><regexi> >>> re.search('foo|bar|baz', 'bar') <_sre.SRE_Match object; span=(0, 3), match='bar'> >>> re.search('foo|bar|baz', 'baz') <_sre.SRE_Match object; span=(0, 3), match='baz'> >>> print(re.search('foo|bar|baz', 'quux')) None # 结合交替、分组和任何其他元字符来实现您需要的任何复杂程度。 # (foo|bar|baz)+表示一个或多个字符串 >>> re.search('(foo|bar|baz)+', 'foofoofoo') <_sre.SRE_Match object; span=(0, 9), match='foofoofoo'> >>> re.search('(foo|bar|baz)+', 'bazbazbazbaz') <_sre.SRE_Match object; span=(0, 12), match='bazbazbazbaz'> >>> re.search('(foo|bar|baz)+', 'barbazfoo') <_sre.SRE_Match object; span=(0, 9), match='barbazfoo'> # ([0-9]+|[a-f]+)表示一个或多个十进制数字字符的序列或一个或多个'a-f'字符的序列 >>> re.search('([0-9]+|[a-f]+)', '456') <_sre.SRE_Match object; span=(0, 3), match='456'> >>> re.search('([0-9]+|[a-f]+)', 'ffda') <_sre.SRE_Match object; span=(0, 4), match='ffda'>