re模块(Python中的正则表达式) re模块
正则表达式本身是一种小型的、高度专业化的编程语言,而在python中,通过内嵌集成re模块,程序媛们可以直接调用来实现正则匹配。正则表达式模式被编译成一系列的字节码,然后由用C编写的匹配引擎执行。
正则表达式中常用的字符含义
1、普通字符和11个元字符:
普通字符 |
匹配自身
|
abc
|
abc
|
.
|
匹配任意除换行符" "外的字符(在DOTALL模式中也能匹配换行符 |
a.c
|
abc
|
转义字符,使后一个字符改变原来的意思
|
a.c;a\c
|
a.c;ac
|
|
*
|
匹配前一个字符0或多次
|
abc*
|
ab;abccc
|
+
|
匹配前一个字符1次或无限次
|
abc+
|
abc;abccc
|
?
|
匹配一个字符0次或1次
|
abc?
|
ab;abc
|
^
|
匹配字符串开头。在多行模式中匹配每一行的开头 | ^abc |
abc
|
$
|
匹配字符串末尾,在多行模式中匹配每一行的末尾 | abc$ |
abc
|
| | 或。匹配|左右表达式任意一个,从左到右匹配,如果|没有包括在()中,则它的范围是整个正则表达式 |
abc|def
|
abc
def
|
{} | {m}匹配前一个字符m次,{m,n}匹配前一个字符m至n次,若省略n,则匹配m至无限次 |
ab{1,2}c
|
abc
abbc
|
[]
|
字符集。对应的位置可以是字符集中任意字符。字符集中的字符可以逐个列出,也可以给出范围,如[abc]或[a-c]。[^abc]表示取反,即非abc。 所有特殊字符在字符集中都失去其原有的特殊含义。用反斜杠转义恢复特殊字符的特殊含义。 |
a[bcd]e
|
abe
ace
ade
|
()
|
被括起来的表达式将作为分组,从表达式左边开始没遇到一个分组的左括号“(”,编号+1. 分组表达式作为一个整体,可以后接数量词。表达式中的|仅在该组中有效。 |
(abc){2} a(123|456)c |
abcabc
a456c
|
这里需要强调一下反斜杠的作用:
- 反斜杠后边跟元字符去除特殊功能;(即将特殊字符转义成普通字符)
- 反斜杠后边跟普通字符实现特殊功能;(即预定义字符)
- 引用序号对应的字组所匹配的字符串。
a=re.search(r'(tina)(fei)haha2','tinafeihahafei tinafeihahatina').group() print(a) 结果: tinafeihahafei
2、预定义字符集(可以写在字符集[...]中)
d
|
数字:[0-9] |
ac
|
a1c
|
D
|
非数字:[^d] |
aDc
|
abc
|
s
|
匹配任何空白字符:[<空格> fv] |
asc
|
a c
|
S | 非空白字符:[^s] |
aSc
|
abc
|
w
|
匹配包括下划线在内的任何字字符:[A-Za-z0-9_] |
awc
|
abc
|
W
|
匹配非字母字符,即匹配特殊字符 |
aWc
|
a c
|
A
|
仅匹配字符串开头,同^ | Aabc |
abc
|
仅匹配字符串结尾,同$ |
abc
|
abc
|
|
匹配w和W之间,即匹配单词边界匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 | abc a!bc |
空格abc空格 a!bc |
|
B
|
[^] |
aBbc
|
abc
|
这里需要强调一下的单词边界的理解:
w = re.findall('tina','tian tinaaaa') print(w) s = re.findall(r'tina','tian tinaaaa') print(s) v = re.findall(r'tina','tian#tinaaaa') print(v) a = re.findall(r'tina','tian#tina@aaa') print(a) 执行结果如下: [] ['tina'] ['tina'] ['tina']
3、特殊分组用法:
(?P<name>)
|
分组,除了原有的编号外再指定一个额外的别名 | (?P<id>abc){2} |
abcabc
|
(?P=name)
|
引用别名为<name>的分组匹配到字符串 | (?P<id>d)abc(?P=id) |
1abc1
5abc5
|
<number>
|
引用编号为<number>的分组匹配到字符串 | (d)abc1 |
1abc1
5abc5
|
4、贪婪匹配与非贪婪匹配
*?,+?,??,{m,n}? 前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配:
a = re.findall(r"a(d+?)",'a23b') print(a) b = re.findall(r"a(d+)",'a23b') print(b) 执行结果: ['2'] ['23'] a = re.match('<(.*)>','<H1>title<H1>').group() print(a) b = re.match('<(.*?)>','<H1>title<H1>').group() print(b) 执行结果: <H1>title<H1> <H1> a = re.findall(r"a(d+)b",'a3333b') print(a) b = re.findall(r"a(d+?)b",'a3333b') print(b) 执行结果如下: ['3333'] ['3333'] ####################### 这里需要注意的是如果前后均有限定条件的时候,就不存在什么贪婪模式了,非匹配模式失效。
re模块中常用功能函数
compile
编译正则表达式模式,返回一个对象的模式。(可以把那些常用的正则表达式编译成正则表达式对象,这样可以提高一点效率。)
格式:
re.compile(pattern,flags=0)
pattern: 编译时用的表达式字符串。
flags 编译标志位,用于修改正则表达式的匹配方式,如:是否区分大小写,多行匹配等。常用的flags有:
标志 |
含义
|
re.S(DOTALL)
|
使.匹配包括换行在内的所有字符 |
re.I(IGNORECASE)
|
忽略大小写 |
re.L(LOCALE)
|
使预定字符类 w W B s S 取决于当前区域设定 |
re.M(MULTILINE)
|
多行匹配,改变'^'和'$'的行为
|
re.X(VERBOSE)
|
详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释 |
re.U
|
使预定字符类 w W B s S d D 取决于unicode定义的字符属性 |
import re tt = "Tina is a good girl, she is cool, clever, and so on..." rr = re.compile(r'w*oow*') print(rr.findall(tt)) #查找所有包含'oo'的单词 执行结果如下: ['good', 'cool']
match
# match,从起始位置开始匹配,匹配成功返回一个对象,未匹配成功返回None match(pattern, string, flags=0) # pattern: 正则模型 # string : 要匹配的字符串 # falgs : 匹配模式 X VERBOSE Ignore whitespace and comments for nicer looking RE's. I IGNORECASE Perform case-insensitive matching. M MULTILINE "^" matches the beginning of lines (after a newline) as well as the string. "$" matches the end of lines (before a newline) as well as the end of the string. S DOTALL "." matches any character at all, including the newline. A ASCII For string patterns, make w, W, , B, d, D match the corresponding ASCII character categories (rather than the whole Unicode categories, which is the default). For bytes patterns, this flag is the only available behaviour and needn't be specified. L LOCALE Make w, W, , B, dependent on the current locale. U UNICODE For compatibility only. Ignored for string patterns (it is the default), and forbidden for bytes patterns.
# 无分组 r = re.match("hw+", origin) print(r.group()) # 获取匹配到的所有结果 print(r.groups()) # 获取模型中匹配到的分组结果 print(r.groupdict()) # 获取模型中匹配到的分组结果 # 有分组 # 为何要有分组?提取匹配成功的指定内容(先匹配成功全部正则,再匹配成功的局部内容提取出来) r = re.match("h(w+).*(?P<name>d)$", origin) print(r.group()) # 获取匹配到的所有结果 print(r.groups()) # 获取模型中匹配到的分组结果 print(r.groupdict()) # 获取模型中匹配到的分组中所有执行了key的组
search
# search,浏览整个字符串去匹配第一个,未匹配成功返回None # search(pattern, string, flags=0)
# 无分组 r = re.search("aw+", origin) print(r.group()) # 获取匹配到的所有结果 print(r.groups()) # 获取模型中匹配到的分组结果 print(r.groupdict()) # 获取模型中匹配到的分组结果 # 有分组 r = re.search("a(w+).*(?P<name>d)$", origin) print(r.group()) # 获取匹配到的所有结果 print(r.groups()) # 获取模型中匹配到的分组结果 print(r.groupdict()) # 获取模型中匹配到的分组中所有执行了key的组 demo
findall
# findall,获取非重复的匹配列表;如果有一个组则以列表形式返回,且每一个匹配均是字符串;如果模型中有多个组,则以列表形式返回,且每一个匹配均是元祖; # 空的匹配也会包含在结果中 #findall(pattern, string, flags=0)
# 无分组 r = re.findall("aw+",origin) print(r) # 有分组 origin = "hello alex bcd abcd lge acd 19" r = re.findall("a((w*)c)(d)", origin) print(r) Demo
re.match与re.search与re.findall的区别:
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
a=re.search('[d]',"abc33").group() print(a) p=re.match('[d]',"abc33") print(p) b=re.findall('[d]',"abc33") print(b) 执行结果: 3 None ['3', '3']
finditer
搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器。找到 RE 匹配的所有子串,并把它们作为一个迭代器返回。
格式:
re.finditer(pattern, string, flags=0)
iter = re.finditer(r'd+','12 drumm44ers drumming, 11 ... 10 ...') for i in iter: print(i) print(i.group()) print(i.span()) 执行结果如下: <_sre.SRE_Match object; span=(0, 2), match='12'> (0, 2) <_sre.SRE_Match object; span=(8, 10), match='44'> (8, 10) <_sre.SRE_Match object; span=(24, 26), match='11'> (24, 26) <_sre.SRE_Match object; span=(31, 33), match='10'> (31, 33)
sub
# sub,替换匹配成功的指定位置字符串 sub(pattern, repl, string, count=0, flags=0) # pattern: 正则模型 # repl : 要替换的字符串或可执行对象 # string : 要匹配的字符串 # count : 指定匹配个数 # flags : 匹配模式
# 与分组无关 origin = "hello alex bcd alex lge alex acd 19" r = re.sub("aw+", "999", origin, 2) print(r)
subn
返回替换次数
格式:
subn(pattern, repl, string, count=0, flags=0)
print(re.subn('[1-2]','A','123456abcdef')) print(re.sub("g.t","have",'I get A, I got B ,I gut C')) print(re.subn("g.t","have",'I get A, I got B ,I gut C')) 执行结果如下: ('AA3456abcdef', 2) I have A, I have B ,I have C ('I have A, I have B ,I have C', 3)
split
# split,根据正则匹配分割字符串 split(pattern, string, maxsplit=0, flags=0) # pattern: 正则模型 # string : 要匹配的字符串 # maxsplit:指定分割个数 # flags : 匹配模式
# 无分组 origin = "hello alex bcd alex lge alex acd 19" r = re.split("alex", origin, 1) print(r) # 有分组 origin = "hello alex bcd alex lge alex acd 19" r1 = re.split("(alex)", origin, 1) print(r1) r2 = re.split("(al(ex))", origin, 1) print(r2) Demo
escape
把string中,除了字母和数字以外的字符,都加上反斜杆。
>>> print(re.escape('abc123_@#$')) abc123_@#$
IP: ^(25[0-5]|2[0-4]d|[0-1]?d?d)(.(25[0-5]|2[0-4]d|[0-1]?d?d)){3}$ 手机号: ^1[3|4|5|8][0-9]d{8}$ 邮箱: [a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+