一、正则表达式
(一)为什么使用正则?
字符串匹配就可以从文本中匹配出想要的字符,为什么要使用正则表达式?因为每一次匹配都要单独完成,不妨设立一个规则。
(二)正则表达式概念
(1)使用单个字符串来描述匹配一系列符合某个语法规则的字符串
(2)是对字符串处理的一种逻辑公式
(3)应用场景:处理文本和数据
(4)正则表达式过程:依次拿出表达式和文本的字符比较,如果每一个字符都能匹配成功,则匹配成功;否则失败。
一句话,正则表达式就是一套规则,而且是个字符串。
二、re模块
re模块是python中根据正则表达式规则写的一个功能或者模块。re模块!=正则表达式。正则表达式是一套规则,而re模块是根据该规则写的一个模块或者工具,通过这个工具来实现正则表达式的使用。
(一)re模块之方法
(1) match
re.match(pattern, string)
只匹配开头 。
得到一个match object.后面加group()才能打印出结果
如:
import re
a = "python" b = re.match("py", a).group() print(b)
(2) search
re.search(pattern, string, flags=0)
在一个字符串中查找匹配;
注意:只匹配一次(返回第一次成功匹配的结果)
得到一个match object.后面加group()才能打印出结果
如:
a = 'hpyt1848451thshhho577n' b = re.search('d+', a).group() print(b) #1848451 后面的577不匹配
(3) findall
re.findall(pattern, string, flags=0)
匹配所有,返回列表
如:
a = 'hpyt1848451thshhho577n' b = re.findall('d+', a) print(b) #["1848451", "577"]
(4)compile
re.compile(pattern, flags=0)
将正则表达式存到一个变量中,重复使用
如:
a = 'hpyt1848451thshhho577n' res = re.compile('d+') #res可以多次使用 b = re.findall(res, a) print(b) #["1848451", "577"]
(5)sub
re.sub(pattern, repl, string, count=0, flags=0)
将字符串中匹配正则表达式的部分值替换为其他值
如:
a = 'hpyt1848451thshhho577n' res = re.compile('d+') #res可以多次使用 b = re.sub(res, '+', a) print(b) #'hpyt+thshhho+n'
(6)split
re.split(pattern, string, maxsplit=0, flags=0)
根据匹配分割字符串,返回分割字符串组成的列表
如:
a = 'hpyt1848451thshhho577n' res = re.compile('d+') #res可以多次使用 b = re.split(res, a) print(b) #['hpyt', 'thshhho', 'n']
(二)re模块之元字符
. ^ $ []
* + ? {}
(1)“.” 通配符
. 匹配任意字符(除了 )。
re.findall("y..o", "python") #["ytho"]
一个.代表一个位置
(2)^
^ 匹配字符串以..开头
re.findall("^p...o", "python") #["pytho"]
(3)$
$ 匹配字符串结尾
re.findall("^p(.*?)n$", "python") #["python"]
这里加(.*?),是万能匹配,表示中间可以是任意内容。如果不加,直接写"^pn$",那么匹配不成功,只能匹配成功pn
(4)重复功能(量词部分)
a. *
* 匹配前一个字符0次或者无限次
re.findall("d*", "daddy") #['d', '', 'dd', '', '']
re.findall("dd*", "daddy") #["d", "dd"]
匹配后,*前面的那个字符可以是空,也可以是多个字符。
b. +
+ 匹配前一个字符1次或者无限次
re.findall("d+", "daddy") #['d', 'dd'] re.findall("dd+", "daddy") #["dd"]
c. ?
? 匹配前一个字符0次或者1次
re.findall("d?", "daddy") #['d', '', 'd', 'd', '', ''] re.findall("dd?", "daddy") #['d', 'dd']
d. {}
{}范围自己给定
{0,} == *
{1,} == +
{0, 1} == ?
{m}匹配前一个字符m次
{m,n}匹配前一个字符m-n次任意一种
re.findall("al{4}", "youallllll") #['allll']
e.补充
在* 和+后加?,即*?和+?,匹配模式变为非贪婪模式。,即尽可能少匹配字符。
贪婪与非贪婪 1.从语法角度看贪婪与非贪婪 被匹配优先量词修饰的子表达式,使用的是贪婪模式;被忽略优先量词修饰的子表达式,使用的是非贪婪模式。 匹配优先量词包括:“{m,n}”、“{m,}”、“?”、“*”和“+”。 忽略优先量词包括:“{m,n}?”、“{m,}?”、“??”、“*?”和“+?”。 2.从应用角度看贪婪与非贪婪 贪婪与非贪婪模式影响的是被量词修饰的子表达式的匹配行为,贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配;而非贪婪模式在整个表达式匹配成功的前提下,尽可能少的匹配。非贪婪模式只被部分NFA引擎所支持。 3. 从匹配原理角度看贪婪与非贪婪 能达到同样匹配结果的贪婪与非贪婪模式,通常是贪婪模式的匹配效率较高。 所有的非贪婪模式,都可以通过修改量词修饰的子表达式,转换为贪婪模式。 贪婪模式可以与固化分组结合,提升匹配效率,而非贪婪模式却不可以。
如:
#.*默认为贪婪匹配 print(re.findall('a.*b','a1b22222222b')) #['a1b22222222b'] #.*?为非贪婪匹配:推荐使用 print(re.findall('a.*?b','a1b22222222b')) #['a1b']
re.findall("al*", "youallllll") #['allllll'] 贪婪模式
re.findall("al*?", "youallllll") #['a'] 非贪婪模式
(5)[] 字符集
a.起或的作用
print(re.findall('a[+*-]b','a+b a*b a-b')) #["a+b", "a*b", "a-b"]
[]内元字符不起作用.
b.[]内的^
[]内的^ 表示取反
print(re.findall('a[^+*-]b','a+b a*b a-b')) #["a+b", "a*b", "a-b", "a=b"] #["a=b"]
匹配不是+*-任意一个符号的那个
c. -
-表示连续中的任意一个
print(re.findall('a[0-9]b','a1b a*b a-b a=b')) #["a1b"] print(re.findall('a[a-z]b','a1b a*b a-b a=b aeb') #["aeb"] print(re.findall('a[a-zA-Z]b','a1b a*b a-b a=b aeb aEb')) #["aeb", "aEb"]
(6)
反斜杆,能将元字符变为普通字符,将普通字符变为元字符。
a.d匹配任意十进制数
b.D匹配任意非数字字符
c.s 匹配空白字符
d.S 匹配非空白字符
e.w 匹配字母数字字符
f.W匹配非字母数字字符
(7)分组()
print(re.findall('ab+','ababab123')) #['ab', 'ab', 'ab']
print(re.findall('(ab)+123','ababab123')) #['ab'],匹配到末尾的ab123中的ab
注意,findall的结果不是匹配的全部内容,而是组内的内容,因此是ab
print(re.findall('(?:ab)+123','ababab123')) #['ababab123']
:?让结果为匹配的全部内容。
print(re.findall('href="(.*?)"', '<a href="http://www.baidu.com">点击</a>')) #['http://www.baidu.com']
(.*?)代表任意一个内容,且最后得到的结果是()内的内容。
print(re.findall('href="(?:.*?)"','<a href="http://www.baidu.com">点击</a>')) #['href="http://www.baidu.com"']
有名分组 (?P<名字>正则表达式)
print(re.search("(?P<name>[a-z]+)", "python32def").group()) #"python"
#可通过group和名字取值
print(re.search("(?P<name>[a-z]+)", "python32def").group(“name”)) #"python"