欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

python -- re正则模块

程序员文章站 2022-07-10 13:50:40
...

python -- re正则模块

什么是正则?

正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE)。正则是用于做字符串匹配,进行字符串操作。

  • 可以为想要匹配的相应字符串集指定规则
  • 该字符串集可能包含英文语句、email地址、命令或任何你想搞定的东西
  • 可以问诸如:这个字符串匹配该模式吗?
  • “在这个字符串中是否有部分匹配该模式?”
  • 也可以使用RE以各种方式来修改或分割字符串。

正则表达式

正则表达式模式被编译成一系列的字节码,然后由用C编写的匹配引擎执行。

正则表达式,由一些普通字符和一些元字符(metacharacters)组成。普通字符包括大小写的字母和数字,而元字符则具有特殊的含义。

  • 普通字符
    • 大多数字母和字符一般都会和 自身匹配,例如正则表达式test会和字符串“test”完全匹配
  • 元字符metacharacters,为了模糊查询
    • ^ $ * + ? {} []   | ()

正则表达式 - 元字符

  • [ ]
    • 常用来指定一个字符集:[abc];[a-z],[abc]是匹配a或b或c,[a-z]是匹配从a~z,一个一个匹配
    • 元字符在字符集中不起作用:[abc$],这里的$就不再表示以c结尾,而表示为$也是匹配对象之一
    • 补集匹配不在区间范围内的字符:[^f],表示处f以外的字符集
import re

s = r'[a-z]'
s_1 = r'[a-z]{2}'
s_2 = r'[^a-z]'
s_3 = r'[ab$]'
s_4 = r'[a-z^]'
st = 'aa00acdab'
st_1 = 'aa00acdab^'

res = re.findall(s, st)
res_1 = re.findall(s_1, st)
res_2 = re.findall(s_2, st)
res_3 = re.findall(s_3, st)
res_4 = re.findall(s_4, st_1)

print(res)
print(res_1)
print(res_2)
print(res_3)
print(res_4)

'''
以下是程序的结果
['a', 'a', 'a', 'c', 'd', 'a', 'b']
['aa', 'ac', 'da']
['0', '0']
['a', 'a', 'a', 'a', 'b']
['a', 'a', 'a', 'c', 'd', 'a', 'b', '^']
'''
  • ^
    • 匹配行首,只有在设置了re.M时候,它才会匹配多行,不然就相当于起始位置。
  • $
    • 匹配行尾, 行尾被定义为 字符串尾,或一个换行字符后面的任何位置
import re

s = r'^hello'
s_1 = r'rld$'
st = 'hello world,hello world'
st_1 = '''hello world;
hello world
hello world'''

res = re.findall(s, st)
res_1 = re.findall(s, st_1)
res_2 = re.findall(s, st_1, re.M)
res_3 = re.findall(s_1, st)

print(res)  # ['hello']
print(res_1)  # ['hello']
print(res_2)  # ['hello', 'hello', 'hello']
print(res_3)  # ['rld']
  •  
    • 反斜杠后面可以加不同的字符表示不同特殊意义
    • 也可以用于取消所有的元字符;\[或 \ - \d 匹配任何十进制,同[0-9]
      • \D 匹配任何非数字,同[^0-9]
      • \s 匹配任何空白字符,同[\t\n\r\f\v]
      • \S 匹配任何非空白字符,同[^\t\n\r\f\v]
      • \w 匹配任何字母数字,下划线,同[a-zA-Z0-9_]
      • \W 匹配任何非字母数字,下划线,同^a-zA-Z0-9_]

正则表达式 - 元字符 重复

正则表达式第一功能是能够匹配不定长的字符集,另一功能就是可以指定正则表达式的一部分的重复次数。

      • 指定前一个字符可以被匹配0次或多次,不止一次。
      • 匹配一次或更多次
      • 与*的区别,*允许匹配0次,+
  • ?
    • 匹配一次或0次,可有可无,用于标记某事物是可选。可以适用于正则中贪婪模式和非贪婪模式。
  • {m,n}
    • m 和n是十进制整数, 至少m次重复,最多n次重复。
    • 忽略m下边界是0,忽略n上边界为无穷的(20亿)
    • {0,},等同于*,{1,}等同于+,而{0,1},等同于? 不建议这样使用,只做理解用。
import re

r = r'ab*'
r_1 = r'ab+'

res = re.findall(r, 'a')
res_1 = re.findall(r, 'ab')
res_2 = re.findall(r, 'abbbb')
res_3 = re.findall(r, 'bbbb')

Res = re.findall(r_1, 'a')
Res_1 = re.findall(r_1, 'ab')
Res_2 = re.findall(r_1, 'abbbb')
Res_3 = re.findall(r_1, 'bbbb')

print(res)  # ['a']
print(res_1)  # ['ab']
print(res_2)  # ['abbbb']
print(res_3)  # []
print(Res)  # []
print(Res_1)  # ['ab']
print(Res_2)  # ['abbbb']
print(Res_3)  # []

正则的贪婪和非贪婪模式

问号 ?实现

import re

r = r'ab+'  # 贪婪模式
r_1 = r'ab+?'  # 非贪婪模式

st = 'abbbbbbbb'

print(re.search(r, st).group())  # abbbbbbbb
print(re.search(r_1, st).group())  # ab

import re

a = 'inet 地址:192.168.12.55 广播:192.168.12.255'
a_1 = 'abcabc123123def456def456'
a_2 = '310104198001011211'

# 可以写成re.match(*******).group()

# re.match从头开始匹配
b = re.match('192', a)
# b.group()

c = re.match('inet', a)
print(c.group())  # inet
# \w只取一个字符,匹配[A-Za-z0-9],不匹配特殊字符
d = re.match('\w', a)
print(d.group())  # i
# \w+只取一个字符,匹配[A-Za-z0-9],匹配前一个字符1次或多次
e = re.match('\w+', a)
print(e.group())  # inet
# .只取一个字符,默认匹配除\n之外的任意一个字符,要多次匹配,只要加+即可
f = re.match('.', a)
f_1 = re.match('.+', a)
print(f.group())  # i
print(f_1.group())  # inet 地址:192.168.12.55 广播:192.168.12.255

# 匹配*号前的字符0次或多次,可以配不到
g = re.match('ab*', a_1)
print(g.group())  # ab

# 匹配?号前一个字符1次或0次
h = re.match('a?', a_1)
print(h.group())  # a

# {m}匹配前一个字符m次
i = re.match('\w{5}', a_1)
print(i.group())  # abcab

# 匹配|左或|右的字符
j = re.match('abc|ABC', a_1)
print(j.group())  # abc

# 查询身份证的套路
l = re.search('(\d{2})(\d{2})(\d{2})(\d{4})', a_2)
print(l.groups())  # ('31', '01', '04', '1980')

# 匹配$前结尾,或用\Z一样,例如:以数字开头,以数字结尾的套路
m = re.search('\d.*\d$', a_2)
m_1 = re.search('\d.*\d\Z', a_2)
print(m.group())  # 310104198001011211
print(m_1.group())  # 310104198001011211

#  '(?P<name>...)' 分组匹配 ,比较好玩
n = re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})",a_2)
print(n.groupdict())  # {'province': '3101', 'city': '04', 'birthday': '1980'}
print(n.groups())  # ('3101', '04', '1980')

# 开始对a变量,取IP地址了
# p = re.search("(\d{3}\.){3}\d{3}", a), 这个语句和下面的区别是{3}一定要匹配3次,{1,3}是匹配1次或2次或3次
p = re.search("(\d{1,3}\.){3}\d{1,3}", a)
print(p.group())  # 192.168.12.55

# 取出所有数字,用列表表示
q = re.findall('\d+', a_1)
print(q)  # ['123123', '456', '456']

r = re.findall('[a-zA-Z]+', a_1)
r_1 =re.findall('\D+', a_1)
r_2 = re.split('\d+', a_1)
print(r)  # ['abcabc', 'def', 'def']
print(r_1)  # ['abcabc', 'def', 'def']
print(r_2 )  # ['abcabc', 'def', 'def', '']

# 用数字为分割,用|取代数字,替换的功能
s = re.sub('\d+', '|', a_1)
s_1 =re.sub('\d+', '|', a_1, count=2)
print(s)  # abcabc|def|def|
print(s_1)  # abcabc|def|def456

# 较为烦人的反斜杠\
t = re.split('\\\\', r'c:\users\username\desktop')
print(t)

re.compile() 正则编译 将正则表达式转成对象

re模块提供了一个正则表达式引擎的接口,可以将REstring编译成对象并用它们进行匹配。编译后的正则速度比非编译的快很多。

什么时候用到正则编译?

当某个正则用的地方较多是,可以考虑用正则编译

import re

# 定义一个正则规则
r = r'\d{3,4}-?\d{8}'
# 定义一个正则编译
p_tel = re.compile(r)
# 使用p_tel正则编译
print(p_tel.findall('021-123456789'))  # ['021-12345678']

# 定义一个不区分大小写的正则编译
sfsc_re = re.compile(r'sfsc', re.I)
print(sfsc_re.findall('SFsc'))  # ['SFsc']

取手机号码

import re

r = '(1[3,8])(?=([0-9]{9}))'

s = 'fafafa1381867845245813800000000fff'

info = re.findall(r, s)

new_info =[]

for i in range(len(info)):
    s = info[i][0]+info[i][1]
    new_info.append(s)

print(new_info)

反斜杠的困扰

用四个\来解析一个,即‘\\\\’来转移一个

re.match() 判断匹配是否成功,一般只用来判断有值还是没有值

match的常用用法:

import re

# 定义一个不区分大小写的正则编译
sfsc_re = re.compile(r'sfsc', re.I)

x = sfsc_re.match('uuuww')
# x = sfsc_re.match('sfsc uuuww')
if x:
    print(' x is not empty')
elif not x:
    print('x is null')

编译标志-flags

  • re.S 使.匹配包含换行\n在内的所有字符
  • re.I 忽略匹配的大小写
  • re.I 做本地化识别,类似法语,西班牙语等
  • re.M 多行匹配,影响^和$
  • re.X 当正则表达式是多行时使用

正则表达式 分组

分组:“(”和“)”

利用分组()提取正则的效果
分组有优先处理正则的效果,所以可以用这一特性来实现一些功能。

import re

email = r'\w{3}@\w+(\.com|\.cn)'

res = re.match(email, '[email protected]').group()
print(res)  # [email protected]

res = re.match(email, '[email protected]').group()
print(res)  # [email protected]

# 奇迹发生了,接下来是见证奇迹的时刻
res = re.findall(email, '[email protected]')
print(res)  # ['.com']

res = re.search(email, '[email protected]').group()
print(res)  # [email protected]

import re

s = '''
hhsdj dskj hello src=oldboy yes jdjsds
guhihjj src=123 yes jkjl
src=443 yes
hello src=python yes nkjn'''

# 定义一个正则表达式
r = 'hello src=.+ yes'

res = re.findall(r, s)
print(res)  # ['hello src=oldboy yes', 'hello src=python yes']

# 利用分组的概念只提起res中src=的值。

r_1 = 'hello src=(.+) yes'
res_1 = re.findall(r_1, s)
print(res_1)  # ['oldboy', 'python']

写在后面

  • 定义一个正则表达式,就等于顶一个字符串
常用正则表达式符号 备注
'.' 默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行
'^' 匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a","\nabc\neee",flags=re.MULTILINE)
'$' 匹配字符结尾,或e.search("foo$","bfoo\nsdfsf",flags=re.MULTILINE).group()也可以
'*' 匹配*号前的字符0次或多次,re.findall("ab*","cabb3abcbbac") 结果为['abb', 'ab', 'a']
'+' 匹配前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb']
'?' 匹配前一个字符1次或0次
'{m}' 匹配前一个字符m次
'{m,}' 匹配前一个字符至少m次,类似m+
'{n,m}' 匹配前一个字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 结果'abb', 'ab', 'abb']
'[xyz]' 字符集合。匹配所包含的任意一个字符。例如,“[abc]”可以匹配“plain”中的“a”
'[^xyz]' 负值字符集合。匹配未包含的任意字符。例如,“[^abc]”可以匹配“plain”中的“plin”。
'[a-z]' 字符范围。匹配指定范围内的任意字符。
'|' 匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 结果'ABC'
'(...)' 分组匹配,re.search("(abc){2}a(123|456)c", "abcabca456c").group() 结果 abcabca456c
'\A' 只从字符开头匹配,有点类似'^'' re.search("\Aabc","alexabc") 是匹配不到的
'\Z' 匹配字符结尾,同$
'\d' 匹配数字0-9
'\D' 匹配非数字
'\w' 匹配[A-Za-z0-9]
'\W' 匹配非[A-Za-z0-9],等价于“[^A-Za-z0-9_]只匹配特殊字符
'\s' 匹配空白字符、\t、\n、\r , re.search("\s+","ab\tc1\n3").group() 结果 '\t'
'(?P...)' 分组匹配 re.search("(?P[0-9]{4})(?P[0-9]{2})(?P[0-9]{4})","371481199306143242").groupdict("city") 结果{'province': '3714', 'city': '81', 'birthday': '1993'}
常用方法 备注
re.match 从头开始匹配,一般不怎么用,search较多用
re.group 取出匹配的内容
re.search 匹配包含,用的较多
re.findall 把所有匹配到的字符放到以列表中的元素返回
re.split 以匹配到的字符当做列表分隔符
re.sub 匹配字符并替换

上一篇: python_PIL模块

下一篇: nginx配置详解