正则语法
对匹配类型
(1).
:代表除换行外任意一个字符(除了换行符,但是如果开了编译标志DOTALL
后就可以包括换行符了),举例:(search
等正则相关方法具体用法参考后面)
>>> re.search(r's.a','where is abc in')
<_sre.SRE_Match object; span=(7, 10), match='s a'>
所以这里.
对应了一个空格
,如果就要匹配.
这个字符的话可以前面加\
防止被转义,举例:\.
,此时就是.
了
(2)\d
:代表任意一个数字,例如查找一个ip地址:
>>> re.search(r'\d\d\d.\d\d\d.\d\d\d.\d\d\d','192.168.134.253')
<_sre.SRE_Match object; span=(0, 15), match='192.168.134.253'>
(3)\w
:匹配字母、数字或下划线或汉字
(4)\s
:匹配任意的空白符
(5)(匹配的字符)\数字
:给括号里匹配到的字符分组,并在出现\数字
时将改组匹配一次,举例:
>>> re.search(r'a(bc)\1(d)\2(e)\3','abcabcbcddee') #此时\1代表bc、\2为d、\3为e
<_sre.SRE_Match object; span=(3, 12), match='abcbcddee'>
>>> re.search(r'a(bc)\1(d)\1(e)\1','abcabcbcddee') #不对,\1此时代表第一组的bc
>>> re.search(r'a(bc)\1(d)\1(e)\1','abcabcbcdbcebc')
<_sre.SRE_Match object; span=(3, 14), match='abcbcdbcebc'>
(因为括号里的是bc,所以就把bc匹配了两次),也可以用r'a(bc){2}'
替代,效果相同
(6)\ASCII值
:对应ASCII表内容,例如八进制的60对应ASCII的0,则:
>>> re.search(r'abc\060','abcabc0')
<_sre.SRE_Match object; span=(3, 7), match='abc0'>
(7)^
:匹配字符串的开始,也就是只有这个字符串在开始位置才可以查到(\A
默认情况下跟其一样),举例:
>>> re.search(r'^abc','abcde')
<_sre.SRE_Match object; span=(0, 3), match='abc'>
>>> re.search(r'^abc','fabcde') #没有结果,即None(因为abc不为开始符号)
(8)$
:匹配字符串的结束,和上面的相反(\Z
默认情况下跟其一样),举例:
>>> re.search(r'abc$','abscdeabc')
<_sre.SRE_Match object; span=(6, 9), match='abc'>
(9)\b
:匹配单词的边界,除了字母、_
和数字以外都是边界(即\b
可以替代这三种类型),举例:
>>> re.findall(r'\babc\b','abc.abc!abc3() abc_bbc')
['abc', 'abc']
只有前两个abc被找出,但是第三个后面有数字,第四个有下划线,所以abc3,abc_bbc都被看作一个单词——其实只要符合变量标准的都被看作一个单词,即字母数字下划线连在一起的
(10)\B
:匹配非单词的边界,和上面那个相反,使用时只在非单词尾加,举例:
>>> re.findall(r'abc\B','abc.abc!abc3() abc_bbc')
['abc', 'abc'] #只有后两个被找出,因为前两个是单词
(11)\w
:匹配所有字类字符和下划线,像空格、标点符号啥的不匹配,举例:
>>> re.findall(r'\w','abc.a!!你好_-お')
['a', 'b', 'c', 'a', '你', '好', '_', 'お'] #可以发现像!、.、-这些都没了
(12)\W
:和上面的相反,举例:
>>> re.findall(r'\W','abc.a!!你好_-お')
['.', '!', '!', '-']
对匹配范围
(1)[存在的字符或者范围]
:查找对应[]
的一个字符
(2)[含有的字符]
:可以放几个字符,但记住大小写敏感,举例:
>>> re.findall(r'[Wabcde]','www.baidu.com')
['b', 'a', 'd', 'c'] #W不匹配w
因为[]
里面的字符都是看作普通字符看待,所以[.]
也只是匹配.
,而不是任意字符,比如:
>>> re.findall(r'[Wabcde.]','www.baidu.com!@#')
['.', 'b', 'a', 'd', '.', 'c'] #结果并没有匹配!、@、#
(3)[字符1-字符2]
:左边的ASCII要比右边的小,可以匹配字符范围,举例1:
>>> re.findall(r'[a-z]','www.baidu.com')
['w', 'w', 'w', 'b', 'a', 'i', 'd', 'u', 'c', 'o', 'm']
因为里面字符是按ASCII码表排序的,所以比如a的A大,所以[A-a]
可以,但[a-A]
不可以,举例2:
>>> re.findall(r'[A-a]','www.baidu.com')
['a']
>>> re.findall(r'[a-A]','www.baidu.com')
sre_constants.error: bad character range a-A at position 1 #报错
但因为匹配的是一个字符,所以数字的范围只有[0-9]
,一堆数字只会看作一个一个通配符,举例:
>>> re.findall(r'[0-3856]','ww32w.baidu.com')
['3', '2'] #匹配0到3还有8/5/6中的一个数,而不是匹配0到3856的数
(4)[^不含有的字符]
:可以匹配不含有的字符,举例:
>>> re.findall(r'[^a-z.]','www.baidu.com!@#')
['!', '@', '#'] #不含所有小写字母和.
注:
^
得放在第一个才有效果,否则只是单纯的匹配^
这个符号
对匹配长度
(1)匹配字符{匹配长度}
:可以匹配字符的长度,{}
前的一个字符是我们要匹配的字符,{}
里可以是一个数字,代表有几个,也可以是两个数字(用逗号隔开),代表长度可取的范围({1,5}
代表至少1个最多5个,{1,}
代表最少1个),比如前面ip地址我们就能更精准的匹配了:
>>> re.findall(r'[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}','192.168.134.253')
['192.168.134.253']
但如果要更精准,要匹配0-255
的数就可以:
for each in range(257):
q = re.findall(r'[1]\d{2}|2[0-4]\d|25[0-5]|\d{1,2}',str(each))
print(each,'-->',q)
部分结果:
0 --> ['0']
1 --> ['1']
2 --> ['2']
...
255 --> ['255']
256 --> ['25', '6']
#可以发现只有0-255匹配成功
#匹配法则:
#1开头时,个位和十位数值随意
#2开头,十位在0-4的个位随意,25开头的个位只能是0-5
#还有两位数和一位数的
#把以上几种或起来
此时更精准的ip
匹配就可以是:
>>> q = re.search(r'(([1]\d{2}|2[0-4]\d|25[0-5]|\d{1,2})\.){3}([1]\d{2}|2[0-4]\d|25[0-5]|\d{1,2})','192.168.1.1')
>>> q.group()
'192.168.1.1'
#0-255加.重复3次,最后面再来个0-255但不加.
#其中每个0-255用()括起来,前面重复3次的内容也用括号括起来,不然只会把.重复3次
(2)匹配字符*
:匹配前面的字符0次或多次,相当于{0,}
,举例:
>>> re.findall(r'abc*','asfabccd')
['abcc']
#此时c有2个所以都被匹配
(3)匹配字符+
:匹配前面的字符1次或多次,相当于{1,}
(4)匹配字符?
:匹配前面的字符0次或1次,相当于{0,1}
注:
(2)和(3)的匹配方法有种贪婪的特性,有时可能会把字符匹配多了,比如字符串str1 = ''
,我们只要匹配,所以可能用:
re.search('<.+>',str1)
(以<
开头,后面一个或多个任意字符,最后以>
结尾),结果匹配的是:''
,说明匹配东西多了(因为此时他会尽可能多的匹配,所以不会从左到右直到碰到第一个>
就结束,其相当于从最右面开始找第一个>
然后结束),所以为了避免这种情况,就会用到?
(此时?
不代表0或1次,而是代表非贪婪模式),即:re.search('<.+?>',str1)
,这样就会从左到右当遇到第一个>
时结束,所以此时结果就是''
了
常用方法
(import re
)
虽然像find()
也能起到查找字符的功能,但re
模块下的函数(比如search
)可以使用正则表达式,具体如下:
1.search('要查找的字符', '从哪里查找')
结果返回这个查的字符在查找的哪些位置,举例:
>>> re.search(r'abc','where is abc in') #开头加`r`防止字符串转义等问题
<_sre.SRE_Match object; span=(9, 12), match='abc'>
#第一个分号前不用管,span代表位置,match代表匹配的字符,没有就返回none
注:
(1)如果要只获得查找到的字符结果可以用group()
函数,举例:
>>> p = re.search(' (\w+) (\w+)','may i help you')
#匹配第一位为空格,第二位是一直到非空格、符号位,接着空格,然后再一直到非空格、符号位的字符串
>>> p.group()
' i help'
group()
如果捕获的里面有子组,还可以分开看子组内容,例如对上面的:
>>> p.group(1)
'i'
>>> p.group(2)
'help'
(2)如果要获得span
里的参数,也就是匹配的是第几位到第几位,就可以用span,如果只要知道开头或结尾位置,那么可以用start
和end
,一个代表从第几位开始匹配,一个是第几位结束匹配,例如还是对上面的p:
>>> p.span()
(3, 10)
>>> p.start()
3
>>> p.end()
10
注2:
内置函数find()
也可以实现,会返回起始位置,举例:
>>> 'where is abc in'.find('abc')
9
2.findall('要匹配的字符', '从哪里查找')
结果以一个列表形式返回所有匹配上的字符(都是单个字符),举例:
>>> re.findall('a.c','abc,acc,a5c')
['abc', 'acc', 'a5c']
并且该函数有个十分智能的方法,就是可以只返回一个我们想要的内容序列,比如上面返回的都是a开始,c结束,中间一个任意字符的数组,现在我们只要中间的那个字符,就可以在我们想要的那个字符上加上括号,例如:re.findall('a(.)c','abc,acc,a5c')
,此时结果就是我们想要的['b', 'c', '5']
了(当然这是在返回的字符串有子组的前提下)
注:
因为有子组前提下有括号的地方都会被单独弄出来,假如要弄一个ip地址:
>>> re.findall(r'(([01]?\d?\d|2[0-4]\d|25[0-5])\.){3}([01]?\d?\d|2[0-4]\d|25[0-5])','192.31.123.112')
[('123.', '123', '112')]
结果并不是我们想要的效果,其实是他自认为括号的3个地方是我们想要的,所以就把这3个地方分开组成一个元组给我们,为了避免这种情况发生,我们应该在不想被智能读取的括号开头加上个?:
,还是刚才那个举例:
>>> re.findall(r'(?:(?:[01]?\d?\d|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d?\d|2[0-4]\d|25[0-5])','192.31.123.112')
['192.31.123.112']
3.compile('正则表达式')
这个是编译正则表达式的函数,可以提前把正则表达式存到一个类中,当需要重复使用某一个表达式规则时,使用这函数就比较方便,举例:
p = re.compile('[a-z]') #此时把该表达式存到p里,p变成存放该表达式的类
p.findall('www.BaiDu.com') #不用再从re模块调用,直接调用p就可以使用该表达式规则
结果为:
['w', 'w', 'w', 'a', 'i', 'u', 'c', 'o', 'm']
#匹配所有小写字母
4.sub('正则表达式', '替换成的内容', '字符串')
可以把符合正则的字符都替换成其他字符,举例:
>>> a = re.compile('\(.+?\)')
>>> b = 'abc(fg)de'
>>> re.sub(a, '\t', b) #把所有括号连同其包起来的内容去掉
'abc\tde'
5.编译标志
(使用方法:re.compile('正则表达式','re.编译标志')
)
(1)DOTALL
此时.
可以匹配包括换行符的任何符号(也就是所有符号),举例:
q = re.compile(r'a.b',re.DOTALL)
q.findall('a\nb,a b')
结果为:
['a\nb', 'a b']
#可以发现'\n'现在也能匹配了
(2)IGNORECASE
:此时匹配时大小写不区分
(3)VERBOSE
:启用详细的正则表达式,此时空格会被忽略,同一行的#
后面是注释(当然如果还想空格就\
,想#就\#
),举例:
q = re.compile(r"""
(
0[0-7]+ #八进制
|[0-9]+ #十进制
|x[0-9a-fA-F]+ #十六进制
)
; #结尾分号
""", re.VERBOSE)
如上所示,一个正则表达式的编译就美观多了
6.re.S
允许在多行内匹配,相当于匹配时加上\n
举例:
>>> x = """abc
de
fgh
"""
>>> re.findall('a(.*?)h', x)
[]
>>> re.findall('a(.*?)h', x, re.S)
['bc\n\tde\n\tfg']
可以看出原来无法匹配到换行的部分,但是加上re.S
以后,就可以匹配上了
参考:https://blog.csdn.net/qq_40942329/article/details/78870493
文章参考
https://zhuanlan.zhihu.com/p/127807805?utm_source=qq