正则表达式
-
python无正则表达式,通过别的模块re(regex模块)应用过来
- import re # 引入re模块调用正则表达式
-
字符匹配
- 普通字符:如英文字母a-zA-Z和其他字符
regex = 'apple' ret = re.findall(regex, 'i have a apple , i have a pen, apple pen ?') print(ret) ======> ['apple', 'apple']
-
元字符:被赋予特殊含义的字符
- .:通配符(任意字符)
- ^:是否以某个字符开头
- $:是否以某个字符结尾
ret = re.findall('.', 'string') print(ret) # ['s', 't', 'r', 'i', 'n', 'g'] ret = re.findall("^apple", 'apple is one kind of fruit') print(ret) # ['apple'] ret = re.findall("^apple", 'the apple is one kind of fruit') print(ret) # [] ret = re.findall('pen$', 'i have a apple , i have a pen, apple pen ?') print(ret) # [] ret = re.findall('pen$', 'i have a apple , i have a pen, apple pen') print(ret) # ['pen']
- * :出现0次或n次
- +:出现1次或n次
- ?:出现0次或1次
- {}:
- {x}:出现x次
- {x,}:至少出现x次
- {x,y}:出现x-y次之间
ret = re.findall('apple*', 'i have an apple , not applee or appl') print(ret) # ['apple', 'applee', 'appl'] ret = re.findall('apple+', 'i have an apple , not applee or appl') print(ret) # ['apple', 'applee'] ret = re.findall('apple?', 'i have an apple , not applee or appl') print(ret) # ['apple', 'apple', 'appl'] ret = re.findall('apple{2,4}','i have an apple , not appleee or appleeee') print(ret) # ['appleee', 'appleeee']
- \:转义
- 后面如果接元字符,则将元字符转为普通字符
- 后面接普通字符,则实现该字符特殊功能
- 后面接序号,引用所匹配的字符串
- -:表示范围
- ^:取反
- \:转义
- \d:数字[1-9]
- \D:非数字[^1-9]
- \w:字母数字下划线[a-zA-Z_]
- \W:非字母数字下划线[^a-zA-Z_]
- \s:空白字符[\t\n\r\f\v]
- \S:非空白字符[\t\n\r\f\v]
- \b:匹配单个单词边界,就是单词间间隔,边界不一定是空格,特殊字符也可以
- ():组
ret = re.findall('\d', '123sadf@#$') print(ret) # ['1', '2', '3'] ret = re.findall('[^\d]+','asdf123d5esd234') print(ret) # ['asdf', 'd', 'esd'] ret = re.search(r'(alex)(eric)com\1', 'alexericcomalex').group() print(ret) # alexericcomalex
- 非贪婪匹配
- 一般 *和+匹配的时候都按照最多的原则匹配获取(贪婪匹配)
- 如果想要按最少匹配,则加上?但是有条件
\d+?:一个或者多个,取最少的1个 \d*?:0个或者多个,取最少的0个 'a(\d+?)':可以用非贪婪匹配 'a(\d+?)b'不可以用非贪婪模式,因为后面接了字符
-
re包方法:
- findall():查找所有,返回一个列表
- search():找到第一个就不往下找了
- match():只匹配开头的内容
-
search() 和 match()如果匹配成功或返回一个对象,该对象方法
- group():返回组的内容
- groups():根据regex的分组情况返回tuple
ret = re.search('(ap)+(pl)+e', 'apple apaplele').group() print(ret) # apple ret = re.search('(ap)+(pl)+e', 'apple apaplele').groups() print(ret) # ('ap', 'pl')
- start():匹配到的第一个索引位置
- end():匹配的结束位置索引
- span():start 和 end索引之间的区间
ret = re.search('(ap)+(pl)+e', 'apple apaplele') print(ret.start()) # 从开始 print(ret.end()) # index = 4结束,开区间为5 print(ret.span()) #[0,5)
a = '123abc456' regex = '([\d]*)([a-zA-Z]*)([\d]*)' ret = re.search(regex, a) print(ret.group()) # 默认为0 print(ret.group(1)) print(ret.group(2)) print(ret.group(3)) print(ret.groups()) """ 123abc456 123 abc 456 ('123', 'abc', '456') """ a = '123abc456' regex = '([\d])*([a-zA-Z])*([\d])*' ret = re.search(regex, a) print(ret.group()) # 默认为0 print(ret.group(1)) print(ret.group(2)) print(ret.group(3)) print(ret.groups()) """ 123abc456 3 c 6 ('3', 'c', '6') """
-
re的其他方法:
- sub(pattern, repl, string, max=0):替换
- max表示替换的最大次数,默认为0,不限次数
ret = re.sub('g.t', 'have', 'i get a pen, i got a pen, i gun a pen') print(ret) # i have a pen, i have a pen, i gun a pen
- subn(pattern, repl, string):替换,返回的结果带替换次数num
ret = re.subn('g.t', 'have', 'i get a pen, i got a pen, i gun a pen') print(ret) # ('i have a pen, i have a pen, i gun a pen', 2)
- compile(regext):编译.传入一个正则表达式,返回一个匹配器
regex = re.compile('\w*oo\w*') ret = regex.findall('JGood is a handsome boy, he is cool') print(ret) # ['JGood', 'cool']
- split:切割
ret = re.split('\d', 'one1two2three3four4') print(ret) # ['one', 'two', 'three', 'four', '']
- sub(pattern, repl, string, max=0):替换
IP正则表达式
# IP 正则表达式
regex = '(([01]?\d?\d|2[0-4]\d|25\d)\.){3}([01]?\d?\d|2[0-4]\d|25\d)'
ret = re.search(regex, '192.168.97.196').group()
print(ret) # 192.168.97.196
-
原生字符串
- 执行下面的代码会报错(在python中)
file = open('C:\tmp\abc.txt', mode='r') # OSError: [Errno 22] Invalid argument: 'C:\tmp\x07bc.txt'
-
原因:
- 在python中,反斜杠\有转义的含义,当遇到\a根据ascii码表,会转为有特殊含义的字符0x07响铃符BEL
-
解决:
- file = open(r'C:\tmp\abc.txt', mode='r')
- r为rawString = 原生字符串,表示传入python的字符是原生的,没有特殊的含义
执行下面的代码会报错(在正则中)
re.findall('\', 'abc\123') # 编译的时候就会出错
-
原因:
- 反斜杠\在正则中也有转义的效果,代表后面接的字符有特殊含义
- 所以使其表示反斜杠应写成\\(双反斜杠,第一个用作转义)
re.findall('\\', 'abc\123') # 执行会报错
- 代码在正则下匹配是正确的,但是执行代码,程序会报错
- 原因:
- 虽然正则表示的写法是正确的,但是程序是运行在python下的
- 在python代码中,我们写的是\\(双反斜杠)表示反斜杠,这只是在python代码中
- 当python代码传递过去给正则表达式,其实是一条反斜杠的转义符,但是正确的表达式需要2条,所以python代码需要写成4条反斜杠才能匹配成功
- 修改代码后为:
re.findall('\\\\', 'abc\123') # ok
-
原生字符串r的产生
- 通过上面的写法,会很麻烦,于是就产生了远程字符串的概念
ret = re.findall(r'\\', r'abc\123') # ['\\']其中一个是转义,表示一个反斜杠
- 代码中,r表示后面字符串的内容就是代表反斜杠,没有别的意思,代码执行的时候,python把2个反斜杠原封不动的传给正则,正则拿到反斜杠,第一个用作第二个的转义
- 这样代码执行的时候会更加直观
执行下面代码
ret = re.findall('\\d', 'w3t5e7') print(ret) ret = re.findall(r'\d', 'w3t5e7') print(ret) ret = re.findall('\d', 'w3t5e7') print(ret) ======== ['3', '5', '7'] ['3', '5', '7'] ['3', '5', '7']
- 原因:
- 第一个传入两个反斜杠,python转义之后,传到正则后是一个反斜杠
- 一个反斜杠转义d,表示数字
- 第二个通过r指定反斜杠是原生字符串,反斜杠直接传到正则表达式转义d
- 第三个理论上会报错,但是反斜杠d在ascii码表上没有特殊含义,python内部会将其原封不动传给正则表达式,但是如果遇到时\a之类的就报错了
- 所以严格来说按12的写才是正确的
-
findall用法
- findall优先把组里的内容取出来
regex = 'www.(baidu|youku).com' ret = re.findall(regex, 'www.baidu.com') print(ret) # ['baidu']
- 如果要去掉优先捕获
regex = 'www.(?:baidu|youku).com' ret = re.findall(regex, 'www.baidu.com') print(ret) # ['www.baidu.com']