今天来整理一下
正则
。有一天被同事问到正则的空格怎么匹配,然而因为长时间没有使用,一个简单的空格都不知道怎么匹配了,于是乎我就\a \b \c
的一个一个回想,还没想到\s
,同事说:算了吧,我还是问度娘吧。
一、什么是正则
- 首先,要知道什么是正则,这是我搜集的一些正则的解释。
正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE)。
正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”, 这个“规则字符串”用来表达对字符串的一种过滤逻辑。
1. 给定的字符串是否符合正则表达式的过滤逻辑(称作“匹配”)。
2. 可以通过正则表达式,从字符串中获取我们想要的特定部分。
总之,正则表达式
就是:定制规则,筛选出自己想要的字符串。还有:正则,和编程语言无关。
既然要定制规则,那么正则都有哪些匹配规则呢?别着急,往下走👇。
二、正则表达式匹配规则
-
1,元字符,用特殊符号表示一类元素
.
: 匹配除换行符以外的任意字符(这是一个小红点儿)
\w
:匹配字母或数字或下划线 (可以记成word
)
\s
:匹配任意的空白符 (可以记成space
)
\d
:匹配数字 (可记成digit
)
\n
:匹配一个换行符
\t
:匹配一个制表符
\b
:匹配一个单词的边界
^
:匹配字符串的开始
$
:匹配字符串的结尾
\W
:匹配非字母数字下划线
\D
:匹配非数字
\S
:匹配非空白符
a|b
:匹配字符a或字符b。(长的写前面,短的写后面)
()
:匹配括号内的表达式,也表示一个组
[...]
:匹配字符组中的字符
[^...]
:匹配除了字符组中字符的所有字符 -
2,字符组 [],限制范围,某个位置只能出现这个范围内的某个元素。
[0123456789]
: 只能匹配0-9数字,可写成[0-9]
[a-z]
:只能匹配小写字母
[A-Z]
:只能匹配大写字母
[0-9a-fA-F]
:可以匹配16进制的某个数 -
3,量词,表示数量,约束前面元字符出现的次数。
*
:重复零次或多次
+
:重复一次或多次
?
: 重复零次或一次
{n}
: 重复n次
{n,}
:重复至少n次
{n,m}
:重复n到m次
说到这个正则的量词,就不得不说两个名词,贪婪匹配
和 非贪婪匹配(惰性匹配)
。
-
那么什么是贪婪匹配呢?
量词的贪婪匹配,可以匹配多次的,有多少次就匹配多少次,没有的才将就匹配最少的【尽可能多的匹配】 -
那什么是非贪婪匹配呢?
量词的惰性匹配,.+?
,.*?
,{n,m}?
【尽可能少的匹配】
就是在量词后加个?
这个东东。他就是惰性匹配了。 -
惰性匹配可以表现为这种形式:
.*?某
--> 直到出现某为止
三、python中如何使用正则
说完正则表达式,来看看python是怎么使用正则的。python中有个re模块
,re中有一些方法,简单说一下。
-
re.findall()
import re
s = '1994-04-04334239238841038-12-3040561009-03-049'
# 一、re.findall(正则表达式,待匹配的字符串,flags=0)
ret = re.findall('1[\d]{3}-[01][\d]-[0123][\d]', s)
print(ret) # 以列表的形式返回所有符合条件的筛选结果。
# 结果:['1994-04-04', '1038-12-30', '1009-03-04']
# 二、findall默认只显示分组中的,分组有优先级。
ret = re.findall('www\.(baidu|oldboy)\.com', 'www.baidu.com')
print(ret)
# 结果:['baidu']
# 三、加上 ?: 取消分组的优先
ret = re.findall('www\.(?:baidu|oldboy)\.com', 'www.baidu.com')
print(ret)
# 结果:['www.baidu.com']
import re
h5 = '<body><table><ul><li><a><name></a></li><li><img src="http://baidu.com/sss/aaa.jpg"/></li></table></boday>'
ret = re.findall('src="(.*?)"', h5)
print(ret[0])
# 结果:http://baidu.com/sss/aaa.jpg
ret3 = re.search('src="(.*?)"', h5)
if ret3:
print(ret3.group(1))
# 结果:http://baidu.com/sss/aaa.jpg
re.S 的使用:
如果不使用re.S参数,则只在每一行内进行匹配,如果一行没有,就换下一行重新开始。
而使用re.S参数以后,正则表达式会将这个字符串作为一个整体,在整体中进行匹配。
import re
big_string_mutil = '''
我是kingname,我的微博号是:123
4567,'''
weibo = re.findall('微博号是:(.*?),', big_string_mutil)
print(weibo) # []
weibo = re.findall('微博号是:(.*?),', big_string_mutil, re.S)
print(weibo) # ['123\n4567']
-
re.finditer()
import re
s ='hdn233jfhf456bj43rjf789ndhd'
ret = re.finditer('\d{2}',s)
print(ret)
# 返回一个存放匹配结果的迭代器:<callable_iterator object at 0x0000022A7FC7D8D0>
print(next(ret).group()) # 查看第一个结果:23
print(next(ret).group()) # 查看第二个结果:45
# print([i.group()for i in ret]) # 查看剩余结果
# 迭代器,节省空间
# for i in ret:
# print(i.group())
a =ret.__next__()
print(a)
# 结果:<_sre.SRE_Match object; span=(15, 17), match='43'>
print(a.group())
# 结果:43
-
re.match()
import re
s = '1994-04-04334239238841038-12-3040561009-03-049'
ret4 = re.match('1[\d]{3}-[01][\d]-[0123][\d]',s)
print(ret4) # 不会直接返回筛选结果:<_sre.SRE_Match object; span=(0, 10), match='1994-04-04'>
# print(ret.group())
if ret4:
print(ret4.group()) # 只从头匹配,如果开头没找到就报错。
# 结果:1994-04-04
ret5 = re.match('a',s)
# print(ret5.group()) # AttributeError: 'NoneType' object has no attribute 'group'
print(ret5)
# 结果:None
# 找不到返回None,group时报错。
-
re.search()
import re
s = '1994-04-04334239238841038-12-3040561009-03-049'
ret2 = re.search('1[\d]{3}-[01][\d]-[0123][\d]', s)
print(ret2) # 不会直接返回筛选结果:<_sre.SRE_Match object; span=(0, 10), match='1994-04-04'>
print(ret2.group()) # group一下才能出来,但是只出来1个:1994-04-04
ret = re.search('q',s)
print(ret) # 找不到返回None,group时报错,None类型当然没有group方法了。
# 结果:None
# print(ret.group()) # AttributeError: 'NoneType' object has no attribute 'group'
ret3 = re.search('A', s)
if ret3:
print(ret3.group()) # 不存在时group()就会报错,所以要加上if
import re
big_sstring_mutil = '''我是kingname,我的微博号是:1234567,我是aaa,我的微博号是:bbb,我是ccc,我的微博号是:ddd,'''
r = re.search('我是(.*?),我的微博号是:(.*?),',big_sstring_mutil)
print(r.group()) # 我是kingname,我的微博号是:1234567, --> 全部结果
print(r.group(1)) # kingname --> 取第一个括号中的内容
print(r.group(2)) # 1234567 --> 取第二个括号中的内容
-
re.split()
import re
s ='hdnjfhfbjrjfndhd'
# 一、分割
ret = re.split('d.',s)
print(ret) # 以正则表达式d.为分割,分割成列表
# 结果:['h', 'jfhfbjrjfn', 'd']
# 二、组合分割
ret1 = re.split('[dj]',s)
print(ret1) # 如果正则表达式在字符组里,先以d分割再以j分割。
# 结果:['h', 'n', 'fhfb', 'r', 'fn', 'h', '']
# 三、分组在 split 中也有特权
rett = re.split('(d.)',s) # 会保留分组内的内容
print(rett) # ['h', 'dn', 'jfhfbjrjfn', 'dh', 'd']
# 四、取消特权
ret2 = re.split('(?:d.)',s) # 这样就不会保留分组内的内容了,取消优先
print(ret2) # ['h', 'jfhfbjrjfn', 'd']
-
re.sub()、re.subn()
import re
s = 'hdnjfhfbjrjfndhd'
# re.sub()
ret2 = re.sub('d..', 'H', s, 1) # 【表达式表示替换内容,要替换的新元素,替换对象,替换次数】
print(ret2)
# 结果:hHfhfbjrjfndhd
ret4 = re.sub('d..', str(2), s, 1) # 【替换成的内容必须是字符串】
print(ret4)
# 结果:h2fhfbjrjfndhd
# re.subn()
ret3 = re.subn('d..', 'H', s) # 【返回元组,前面是替换完的结果,后面是替换的次数】
print(ret3)
# 结果:('hHfhfbjrjfnH', 2)
import re
s = '''wo men 123 shi zu guo de 32144 hua guo,
wo men 34523 shi zu guo de 3256144 hua guo,
wo men 4234 shi zu guo de 44345 hua guo,
wo men 12345433 shi zu guo de 4323125 hua guo,'''
ret = re.sub('\d+', "afanti", s)
print(ret)
结果:
wo men afanti shi zu guo de afanti hua guo,
wo men afanti shi zu guo de afanti hua guo,
wo men afanti shi zu guo de afanti hua guo,
wo men afanti shi zu guo de afanti hua guo,
-
re.compile()
# 将正则表达式编译成一个正则表表达式对象。
# 如果一个正则表达式在程序中只用一次,就没必要编译了。
# 如果同一个正则表达式要被多次使用时,就需要对表达式进行编译,以便后续使用。
import re
s ='hdn233jfhf456bj43rjf789ndhd'
obj = re.compile('\d{2}')
ret = obj.findall(s)
print(ret)
# 结果 :['23', '45', '43', '78']
# 编译,节省时间
四、再来举几个栗子
-
匹配数字
import re
exp = "1-2*(60+(-40.35/5)-(-4*3))"
ret = re.findall('\d',exp)
print(ret) # 只有单个数
# 结果:['1', '2', '6', '0', '4', '0', '3', '5', '5', '4', '3']
ret1 = re.findall('\d+',exp)
print(ret1) # 只有整数(有多位)
# 结果:['1', '2', '60', '40', '35', '5', '4', '3']
ret2 = re.findall('\d+\.\d+',exp)
print(ret2) # 只有小数
# 结果:['40.35']
r = re.findall('\d+|\d+\.\d+',exp)
print(r) # 短的放前面只会出现短的,长的不会出现
# 结果:['1', '2', '60', '40', '35', '5', '4', '3']
ret3 = re.findall('\d+\.\d+|\d+',exp)
print(ret3) # 所以如果有长的要把长的放前面
# 结果:['1', '2', '60', '40.35', '5', '4', '3']
ret4 = re.findall('\d+\.\d+|(\d+)',exp)
print(ret4) # findall 优先级,只留下括号里的
# 结果:['1', '2', '60', '', '5', '4', '3']
ret4.remove('')
print(ret4)
# 结果:['1', '2', '60', '5', '4', '3']
r = re.findall('-?\d+\.\d+|-?\d+',exp)
print(r)
# 所有的数字,包括小数和整数。
# 结果:['1', '-2', '60', '-40.35', '5', '-4', '3']
-
匹配标签
import re
ret = re.search("<(\w+)>(\w+)</(\w+)>","<h1>hello</h2>")
print(ret.group()) # group 组 :<h1>hello</h2>
print(ret.group(0)) # 0 默认全部,同上 :<h1>hello</h2>
print(ret.group(1)) # 第 1 组 :h1
print(ret.group(2)) # 第 2 组 :hello
# 现在有个要求,字符串左右必须一致都是h1或都是h2(这就是标签),怎么做?
# 1,用组的位置的方式
ret = re.search(r"<(\w+)>(\w+)</\1>","<h1>hello</h1>")
print(ret.group())
# 结果:<h1>hello</h1>
# 2,用组的名字的方式
# 可以给分组起名字(?P<名字>表达式)【名字在组内】
ret = re.search("<(?P<tag>\w+)>(\w+)</(?P=tag)>","<h1>hello</h1>")
print(ret) # <_sre.SRE_Match object; span=(0, 14), match='<h1>hello</h1>'>
print(ret.group()) # <h1>hello</h1>
print(ret.group('tag')) # h1
-
匹配中文
[\u4e00-\u9fa5]+
s = "ghjk我爱中国gh中华人民共和国万岁jk关关雎鸠fghjke在河之洲eergfds窈窕淑女dtyuimnbv君子好逑"
import re
ret = re.findall('[\u4e00-\u9fa5]+',s)
print(ret)
# ['我爱中国', '中华人民共和国万岁', '关关雎鸠', '在河之洲', '窈窕淑女', '君子好逑']
五、心态很重要!!!!!!
人生苦短,我用python
网友评论