Python 正则表达式¶
如果已经掌握正则了,直接拉到最下面,看简略表格。
简单正则表达式¶
正则表达式,是使用字符串表达的某种模式,可以用于匹配某一类字符串。
比如 abcd 作为一个正则表达式可以匹配 ffabcdef 中的 abcd。
像上面一样,多数字符只能匹配它本身,比如 正则表达式中的 a 匹配目标字符串中的 a, b 匹配 b 。这种情况下,类似于字符串搜索。 但是正则表达式比字符串搜索强大的地方在于提供了一些特殊字符,进行模式匹配。
.
英文的点
.
。可以用于匹配任意字符,- h.llo 可以匹配 hello, hfllo, hgllo …
- h..lo 可以匹配 hello, hablo, hxylo …
*
星号
*
,并不是用来代指字符,而是说前面一个字符可以出现任意多次,即出现次数大于等于0 . 并且*
可以和.
组合使用。- ap*le 可以匹配 ale, aple, apple, appple, …
- a.*le 可以匹配 ale, azzzzzzzle, abbbble, aaaaaaaaale, …
+
+
和*
很像,含义是 + 前面的字符出现次数大于等于1,和 * 的区别在于,它肯定至少出现一次。- ap+le 可以匹配 aple, apple, apppppppple, 但是不能匹配 ale,
- a.+le 可以匹配 azle, azzzzzzzzle, abbbbbble, 不能匹配 ale。
?
?
表示前面的字符可以出现 0 ~ 1 次,也就是说可以出现或者不出现。- app?le 可以匹配 aple 和 apple
- ap.?le 可以匹配 aple, apple, apale, apble, …
\
前面提到过几种特殊字符
.*+?
, 当需要匹配到字符串中的 * ,而不希望将它当成正则模式时, 可以使用\
将其转义为普通字符。\
也可以用来转义\
本身app\?le
匹配 app?le , 不能匹配 apple 和 aple .app\\le
可以匹配app\le
app\\?le
可以匹配app\le
和apple
[ ]
方括号用来包含一组字符,当成一个字符来使用。
.
可以理解为[ ]
的特殊版本,.
可以匹配任意字符,[ ]
可以匹配指定字符, 指定的字符填写在方括号内部,如果将所有字符都填写在方括号内部,作用就变成了匹配任意字符。- [abc] 可以匹配 a, b, c
- h[abc]llo 可以匹配 hallo, hbllo, hcllo 不能匹配 habllo habcllo
需要注意的是, 方括号中可以不用
\
转义直接写. * + ? | ^ $ ( ) [ { }
这些特殊字符。 只有] \
两个字符除外。只不过,加上转义符也是没有关系的。 所以,如果记不住的话,还是每次都加上转义符吧,以免出错。h[*?.]llo
可以匹配 h*llo, h?llo, h.llo。h[\*\?\.]llo
和h[*?.]llo
是等价的
方括号也可以和
* + ?
配合使用。可以使用
-
表示区间,如果^
出现在首个字符,表示取反。- [a-z] 表示 abcd…xyz 的所有小写字母。
- [^a-z] 表示除去 abcd…xyz 之外的所有字符。
- [a-zA-Z0-9] 表示 大写字母、小写字母、所有数字
- [a-zA-Z0-9!@#] 表示 大写字母、小写字母、所有数字、!@#三个符号
方括号括起来的字符本身是只能匹配一次的,可以和
*+?
结合使用匹配多次- p[abc]+ 可以匹配 pa, pb, pc, pab, pccc, pbcabbaaac …
{ }
{}
是* + ?
的增强版,它可以指定前一个字符出现的次数。语法是{出现最小次数, 最大次数}
*
等价于{0, }
+
等价于{1, }
?
等价于{0, 1}
如果后面的数字不填写,就相当于无穷大, 如
{5, }
表示前一个字符出现至少5次。也可以只填写单个数字,如 {5} 等价于 {5, 5} ,
( )
将一个模式进行分组,看成是单个模式,单独使用时,并没有实际作用,一般作为其他功能的铺垫。
|
表示 或,和 [] 类似,但是 [] 只能表示单字符之间的或的关系。
chin(a)|(ese) 可以匹配 china, chinese
^
匹配行首。
$
匹配行尾。
另外正则表达式中还有一些快捷代号:
符号 | 描述 | 等价形式 |
---|---|---|
\d |
匹配数字 | [0-9] |
\D |
匹配非数字 | [^0-9] |
\s |
匹配不可见字符,如空格 | [ tnrfv] |
\S |
匹配任何非不可见字符 | [^ tnrfv] |
\w |
匹配所有数字字母下划线 | [a-zA-Z0-9_] |
\W |
匹配所有非数字字母下划线 | [^a-zA-Z0-9_] |
python re模块接口¶
正则表达式是使用字符串来表示的,如 b(an)+a
.但是字符串并不是正则表达式,
需要经过编译后才能变成正则表达式对象。编译前,它仅仅是普通的字符串而已。
import re
# 两者是等价的
reg1 = re.compile('b(an)+a')
reg2 = re.compile('b' + '(an)+' + 'a')
# 编译后的reg1/reg2才是正则表达式。
# 使用match匹配字符串。
match = reg1.match("banana")
正则专用字符串¶
关于转义符,比如正则表达式 8\*8
, 使用了斜杠转义 * , 在普通字符串中,斜杠本身也是转义符,
所以需要写成 '8\\*8'
, 需要写两遍,比较繁琐。
所以Python额外提供了一种正则表达式专用字符串:在普通字符串前加上r,字符串中的斜杠将不会被当做转义符。
看一下对比
普通字符串 | 正则字符串 |
---|---|
"ab*" |
r"ab*" |
"\\\\section" |
r"\\section" |
"\\w+\\s+\\1" |
r"\w+\s+\1" |
接口¶
match
从某个位置严格匹配一个字符串。通过第二个参数指定开始位置。默认是最开始位置。
匹配成功返回一个保存了位置信息的 Match 。 失败返回 None .
reg = re.compile("bc") m = reg.match('bcdef') # m.group() -> bc。 成功 m = reg.match('abcdef) # m -> None 匹配失败
search
从某个位置开始搜索字符串。返回第一个搜索到的串。
m = reg.search('bcdef')相当于顺序执行了以下表达式,但是,只要有一个匹配成功就提前返回:
text = "bcdef" m = reg.match(text, 0) if m: return m m = reg.match(text, 1) if m: return m m = reg.match(text, 2) if m: return m …… …… m = reg.match(text, len(text)-1) if m: return m搜索成功返回 Match , 失败返回None
findall
直接返回搜索到的字符串列表。
reg = re.compile(r'\d+') reg.findall('the 3rd people, 34 years old.') # Out: ['3', '34']
finditer
和search/findall类似,但是会一直迭代返回所有搜索到的子串, 每一个迭代值是一个 Match 。
In [7]: text = 'the 3rd people, 34 years old.' In [9]: for span in reg.finditer(text): ...: print(span) ...: <_sre.SRE_Match object; span=(4, 5), match='3'> <_sre.SRE_Match object; span=(16, 18), match='34'>
其他接口
fullmatch: 字符串和正则表达式完全匹配。 split: 和python自带split差不多,但是可以用正则分割字符串。 sub: 和python自带replace差不多,使用正则替换字符串。 subn: 和sub类似,替换字符串,指定最大替换次数。
正则高级用法-分组¶
正则表达式有分组的概念,前面提到过 ( )
的语法,
单独使用可以将一个模式作为一个分组, 作为一个最小的不可分割单位。
如 (ab)+
可以完全匹配 abababab, 不能完整匹配 abbbbb
分组还有很多其他用途。分组有两种: 命名分组、匿名分组。 所有分组都会被记录下来,会自动分配一个编号,从前往后分别为 1、 2、 3 ……, 可以通过编号引用匿名分组。
在结果中提取分组
举例, 下面的正则表达式可以提取出来 多少个苹果交换了多少个香蕉。 其中苹果个数是第一个分组,香蕉个数是第二个分组。
(\d) apple exchange (\d) banana
In [1]: reg = re.compile(r'(\d) apple exchange (\d) banana') In [2]: m = reg.match('6 apple exchange 7 banana') In [3]: m Out[3]: <_sre.SRE_Match object; span=(0, 25), match='6 apple exchange 7 banana'> In [4]: m.groups() Out[4]: ('6', '7')
上面的例子,可以通过 match.groups() 提取出所有分组的匹配结果。 这对于从字符串中抽取信息非常有用。
命名分组
通过
(?P<name>...)
的方式可以创建命名分组。 结果也可以通过 match.groups() 获取, 同时命名分组还可以使用 match.groupdict() 提取分组匹配结果, 可读性更好。In [1]: reg = re.compile(r'(?P<apple_num>\d) apple exchange (?P<banana_num>\d) banana') In [2]: m = reg.match('6 apple exchange 7 banana') In [3]: m.groups() Out[3]: ('6', '7') In [4]: m.groupdict() Out[4]: {'apple_num': '6', 'banana_num': '7'}
正则表达式内部分组引用
正则表达式内部可以使用 1, 2, 3 对特定编号的分组进行引用。
比如上面的例子,要求 apple 和 banana 的数量必须相等。就可以使用下面的正则。
reg = re.compile(r'(\d) apple exchange \1 banana') # 使用 \1 占位表示此处和第一个分组的内容一样。 m = reg.match('6 apple exchange 7 banana') # => 匹配失败 因为 6/7 不一样 m = reg.match('6 apple exchange 6 banana') # out: <_sre.SRE_Match object; span=(0, 25), match='6 apple exchange 6 banana'> m.groups() # => ('6',)
对于命名分组的引用还可以使用另外一种可读性更好的形式:
(?P=name)
# 引用 apple_num reg = re.compile(r'(?P<apple_num>\d) apple exchange (?P=apple_num) banana') m = reg.match('6 apple exchange 7 banana') # => 匹配失败 因为 6/7 不一样 m = reg.match('6 apple exchange 6 banana') # out: <_sre.SRE_Match object; span=(0, 25), match='6 apple exchange 6 banana'> m.groups() # => ('6',) m.groupdict() # => {'apple_num': '6'}
除了上面所说的,正则表达式还存在向前尝试匹配的行为。见下面的附表。
正则表达式附表¶
正则表达式 | 作用 |
---|---|
. |
匹配任意字符 |
^ |
匹配开头 |
$ |
匹配结尾 |
* |
前一个字符出现任意次,也可以不出现 |
+ |
前一个字符出现至少一次 |
? |
前一个字符出现一次或者不出现 |
*? , +? , ?? |
默认情况下, 即尽可能匹配更少字符。 |
{m} |
前一个字符出现m次 |
{m,n} |
前一个字符出现 m~n 次,此区间为闭区间。 |
{m,n}? |
将此模式转换为非贪婪模式 |
\ |
转义符 |
[] |
匹配中括号中的字符 |
∣ |
表示或的关系 |
() |
一般用于创建分组 |
(?...) |
单独使用并没有什么实际含义,根据 一般来说除了 (?P<name>…) 之外,这类表达式都不会被作为分组 |
(?:...) |
默认括号包含的模式都会变成分组,使用这个表达式将不会作为分组。 |
(?P<name>...) |
创建命名分组 |
(?P=name) |
引用命名分组 |
(?#...) |
在正则表达式中增加注释, |
(?=...) |
试探后面的字符是否符合某种模式,不会消耗字符。 比如 因为它仅仅是向前试探而不消耗th两个字符, 并且不能匹配 1st 中的 1。 |
(?!...) |
试探后面的字符不符合某种模式。 |
(?<=...) |
试探前面的字符是否符合某种模式 |
(?<!...) |
试探前面的字符是否不符合某种模式 |
(?(id/name)yes-pattern∣no-pattern) |
引用前面的分组,如果引用成功(即分组存在), 则当前使用 yes-pattern 中的模式匹配, 否则使用 no-pattern 中的模式匹配 |
\number |
使用数字编号引用分组 |
\A |
匹配字符串开头 |
\b |
匹配单词开头结尾。 如 但是不能匹配 ‘foobar’ or ‘foo3’ |
\B |
和 \b 相反,匹配单词的非开头结尾部分。 |
\d |
匹配数字 |
\D |
匹配非数字 |
\s |
匹配不可见字符,如空格 |
\S |
匹配任何非不可见字符 |
\w |
匹配所有数字字母下划线 |
\W |
匹配所有非数字字母下划线 |