re模块
就其本质而言,正则表达式(或 RE)是一种小型的、高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。
字符串是编程时涉及到的最多的一种数据结构,对字符串进行操作的需求几乎无处不在。比如判断一个字符串是否是合法的Email地址,虽然可以编程提取@
前后的子串,再分别判断是否是单词和域名,但这样做不但麻烦,而且代码难以复用。
正则表达式是一种用来匹配字符串的强有力的武器。它的设计思想是用一种描述性的语言来给字符串定义一个规则,凡是符合规则的字符串,我们就认为它“匹配”了,否则,该字符串就是不合法的。
因为正则表达式也是用字符串表示的,所以,我们要首先了解如何用字符来描述字符。
字符匹配(普通字符,元字符):
1 普通字符:大多数字符和字母都会和自身匹配
>>> re.findall('alvin','yuanaleSxalexwupeiqi')
['alvin']
2 元字符:. ^ $ * + ? { } [ ] | ( )
元字符之. ^ $
元字符之* + ? { }
要匹配变长的字符,在正则表达式中,用*
表示任意个字符(包括0个),用+
表示至少一个字符,用?
表示0个或1个字符,用{n}
表示n个字符,用{n,m}
表示n-m个字符:
# 匹配一个数字包括整型和浮点型 ret=re.findall('d+.?d*','12.45,34,0.05,109') print(ret) 运行结果: ['12.45', '34', '0.05', '109']
贪婪匹配
正则匹配默认是贪婪匹配,也就是匹配尽可能多的字符。
非贪婪匹配
在满足匹配时,匹配尽可能短的字符串,使用?来表示非贪婪匹配
ret1=re.findall('131d+','1312312312') #-------------------------------------------------贪婪匹配 print(ret1) ret=re.findall('131d+?','1312312312') #-------------------------------------------------非贪婪匹配/惰性匹配 print(ret) 运行结果: ['1312312312'] ['1312']
注意:前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配
几个常用的非贪婪匹配Pattern
*? 重复任意次,但尽可能少重复 +? 重复1次或更多次,但尽可能少重复 ?? 重复0次或1次,但尽可能少重复 {n,m}? 重复n到m次,但尽可能少重复 {n,}? 重复n次以上,但尽可能少重复
.*?的用法:
. 是任意字符 * 是取 0 至 无限长度 ? 是非贪婪模式。 何在一起就是 取尽量少的任意字符,一般不会这么单独写,他大多用在: .*?x 就是取前面任意长度的字符,直到一个x出现
元字符之转义符
1、反斜杠后边跟元字符去除特殊功能,比如.
2、反斜杠后边跟普通字符实现特殊功能,比如d
d 匹配任何十进制数; 它相当于类 [0-9]。 D 匹配任何非数字字符; 它相当于类 [^0-9]。 s 匹配任何空白字符; 它相当于类 [ fv]。 S 匹配任何非空白字符; 它相当于类 [^ fv]。 w 匹配任何字母数字字符; 它相当于类 [a-zA-Z0-9]。 W 匹配任何非字母数字字符; 它相当于类 [^a-zA-Z0-9] 匹配一个特殊字符边界,比如空格 ,&,#等
让我们看一下的应用:
ret=re.findall(r'I','I am LIST') print(ret) 运行结果: ['I']
ret=re.findall(r'c\b',r'abce') print(ret) 运行结果: ['c\b']
# 是特殊符号所以,'abce'前面需要加r
接下来我们试着匹配下“abcle”中的‘cl’:
import re # ret=re.findall('cl','abcle') #---------------------不正确 # print(ret) # ret=re.findall('c\l','abcle') #---------------------不正确 # print(ret) # # ret=re.findall('c\\l','abcle') #---------------------正确 # print(ret) # # # ret=re.findall(r'c\l','abcle') #---------------------正确 # print(ret)
运行结果:
报错
报错
['c\l']
['c\l']
元字符之分组 ()
除了简单地判断是否匹配之外,正则表达式还有提取子串的强大功能。用()
表示的就是要提取的分组(Group)。
m = re.findall(r'(ad)+', 'add') print(m) ret = re.search('(?P<id>d{2})/(?P<name>w{3})', '23/com') print(ret.group()) print(ret.group('id')) 运行结果: ['ad'] 23/com 23
如果正则表达式中定义了组,就可以在Match
对象上用group()
方法提取出子串来。
注意到group(0)
永远是原始字符串,group(1)
、group(2)
……表示第1、2、……个子串。
元字符之|
ret=re.search('(ab)|d','rabhdg8sd') print(ret) print(ret.group()) 运行结果: <_sre.SRE_Match object; span=(1, 3), match='ab'> ab
元字符之字符集[]
# --------------------------------------------字符集[] ret = re.findall('a[bc]d', 'acd') print(ret) # ['acd'] ret = re.findall('[a-z]', 'acd') print(ret) # ['a', 'c', 'd'] ret = re.findall('[.*+]', 'a.cd+') print(ret) # ['.', '+'] # 在字符集里有功能的符号: - ^ ret = re.findall('[1-9]', '45dha3') print(ret) # ['4', '5', '3'] ret = re.findall('[^ab]', '45bdha3') print(ret) # ['4', '5', 'd', 'h', '3'] ret = re.findall('[d]', '45bdha3') print(ret) # ['4', '5', '3']
注意以上一点。
re模块下的常用方法
import re ret=re.findall('a', 'alvin yuan') # 返回所有满足匹配条件的结果,放在列表里 print(ret) #['a', 'a'] ret=re.search('a', 'alvin yuan').group() print(ret) #a # 函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以 # 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。 ret=re.match('a', 'abc').group() # 同search,不过仅在字符串开始处进行匹配 print(ret) #a ret = re.split('[ab]', 'abcd') # 先按'a'分割得到''和'bcd',再对''和'bcd'分别按'b'分割 print(ret) # ['', '', 'cd'] ret = re.sub('d', 'abc', 'alvin5yuan6', 1) print(ret) #alvinabcyuan6 ret = re.subn('d', 'abc', 'alvin5yuan6') print(ret) #('alvinabcyuanabc', 2) obj = re.compile('d{3}') #编译
ret = obj.search('abc123eeee') print(ret.group()) # 123
当我们在Python中使用正则表达式时,re模块内部会干两件事情
如果一个正则表达式要重复使用几千次,出于效率的考虑,我们可以预编译该正则表达式,接下来重复使用时就不需要编译这个步骤了,直接匹配:
1.编译正则表达式,如果正则表达式的字符串本身不合法,会报错;
2.用编译后的正则表达式去匹配字符串。
ret = re.finditer('d', 'ds3sy4784a') print(ret) #<callable_iterator object at 0x0000000001DE5BE0> print(next(ret).group()) #3 print(next(ret).group()) #4
注意:
1 findall的优先级查询:
import re ret = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com') print(ret) # ['oldboy'] 这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可 ret = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com') print(ret) # ['www.oldboy.com']
2 split的优先级查询:
ret=re.split("d+","yuan2egon56alex") print(ret) ret=re.split("(d+)","yuan2egon56alex") print(ret) 结果: ['yuan', 'egon', 'alex'] ['yuan', '2', 'egon', '56', 'alex']
作业:
1、 匹配一段文本中的每行的邮箱 import re ret=re.findall("w+@w+.(?:com|cn|cc)",s) 2、 匹配一段文本中的每行的时间字符串,比如:‘1990-07-12’; ret=re.findall('(?:[1-2]d{3})-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]d|3[0-1])',s) 3、 匹配一段文本中所有的身份证数字。 ret=re.findall('[1-9]d{16}[dx]',s) 4、 匹配qq号。(腾讯QQ号从10000开始) ret=re.findall('[1-9]d{4,}',s) 5、 匹配一个浮点数。 ret=re.findall('d+.?d*',s) 6、 匹配汉字。 ret=re.findall('[u4e00-u9fa5]+',s) 7、 匹配出所有整数 ret=re.findall('-?d+.d*|(-?d+)',s)