正则表达式
正则
为了匹配一个符合规则的字符串
1.精确匹配
abc:匹配abc的子串
2.选择性匹配
red|blue|green:匹配red 或 blue 或green
3.中括号[]匹配
一个[]只匹配1位,[^]:排除,例如:
[0-9]:匹配0-9之间的一个数字
[^0-9]:排除0-9
[a-z] :小写字母
[A-Z]:大写字母
[A-z]:大小写字母 和 _
[0-9A-z]:字母数字和 _
[\u4e00-\u9fa5]: 匹配所有汉字
4.元字符
大小写反义
\d:[0-9]
\D:[^0-9]
\w:[0-9A-z_]
\W:[^0-9A-z]
.:代表任意字符, \n除外
[\d\D]:代表一切字符
\s:空白字符
\S:非空白字符
\b:匹配单词边界。
\B:匹配非单词边界。
5.量词
0代表匹配空格
re? 或 re{0,1}:0-1
re* 或 re{0}:0-多
re+ 或 re{1,}:1-多
re{n}: n位
re{m,n}: m-n
re{m,}: m-多
6.贪婪匹配与非贪婪匹配
贪婪匹配:能匹配多,不匹配少 例如,\d{2,4}, 以匹配4个为主
非贪婪匹配:量词后加? 能匹配少,不匹配多 例如,\d{2,4}?, 以匹配2个为主
7.分组
将字符串内容按照部分分组匹配
分组:() ,几个() 就有几组
命名捕获分组: (?Prex) ,给分组命名
非捕获分组: (?:rex) : 取消分组
反向引用: \num, 反向引用第num组的内容
例如:
AABB (\w)\1(\w)\2
ABAB (\w)(\w)\1\2
8.限定符
^: 以…开头
$: 以…结尾
9.断言
正向断言,正则在前,条件在后
反向断言: 条件在前,正则在后
正向确定断言:rex(?=\d+) 提取后面是数字的rex
正向否定断言:rex(?!\d+) 提取后面不是数字的rex
反向确定断言:(?<=window)\d+ 提取前面是window的数字
反向否定断言:(?<!window)\d+ 提取前面不是window的数字
(?=.*rex):某个字符串必须包含rex
10.符号含义
*:匹配前面的元素零次或多次
+:匹配前面的元素一次或多次
?:匹配前面的元素零次或一次
{}:用于指定前面的元素出现的具体次数或次数范围
.:在默认模式下,匹配除换行符 \n 之外的任何单个字符
|:表示逻辑“或”操作,用于匹配多个可能的表达式中的一个
^:在正则表达式的开始处使用,表示匹配输入字符串的开始位置
$:在正则表达式的末尾使用,表示匹配输入字符串的结束位置
():用于分组(grouping),以便将多个元素视为一个整体进行匹配和引用
[]:表示字符集(character class),用于匹配方括号内的任意单个字符
re模块函数
search(pattern,string,flag)
search:匹配符合条件第一个子串和首尾下标,
返回match对象,找不到返回None
index(‘’):返回第一个下标,找不到报错
find(‘’):返回第一个下标,找不到-1
s = 'a12b23'
res = re.search(r'\d{2}', s)
print(res) # <re.Match object; span=(1, 3), match='12'>
finditer:匹配符合条件所有子串,返回迭代器
迭代器中每一个元素是match对象
s = 'a12b23'
res = re.finditer(r'\d{2}', s)
for r in res:
print(r.group()) # 12 23
re.match(pattern,string,falgs=0)
pattern:匹配正则
string: 匹配的字符串
flags:匹配模式
匹配以 pattern 开头的 子串 ,返回match对象
函数:
group(): 获取最终匹配子串结果
groups():获取分组结果组成的元组
group(index):获取指定索引分组结果
group(name):获取指定名称分组结果
span(): 获取匹配到的子串的首尾下标
s = '1223ab'
res = re.match(r'(\d{2})(\d{2})', s)
print(res) # <re.Match object; span=(0, 4), match='1223'>
print(res.group()) # 1223
print(res.span()) # (0, 4)
print(res.start()) # 0
print(res.end()) # 4
print(res.groups()) # ('12','23')
匹配以 pattern 开头的 以pattern结尾 子串 ,返回match对象
s = '1223'
res = re.fullmatch(r'(\d{2})(\d{2})', s)
print(res) # <re.Match object; span=(0, 4), match='1223'>
print(res.group()) # 1223
findall(pattern,string,flag)
如果没有分组:返回匹配子串组成的列表
如果有一个分组:只返回分组结果组成的列表
如果有多个分组:返回分组元祖组成的列表
总结: 如果有分组,findall只返回分组结果
提取电话号码指定位数、提取身份证年月日信息
s = '13067895786'
res = re.findall(r'(\d{3})(\d{4})\d{4}', s)
print(res) # [('130', '6789')]
# 提取身份证号的 出生年 月 日
s = '41072419980815451x'
res = re.findall(r'\d{6}(\d{4})(\d{2})(\d{2})', s)
print(res[0]) # ('1998', '08', '15')
sub(pattern,repl,string,flags)
返回替换后的结果
pattern:被替换的正则
repl:
要替换的正则或字符串或lambda,lambda 参数为匹配结果
如果使用反向引用,必须 使用 r’\1***\2’
count:替换个数
替换所有数字为#
s = 'hello666 world999'
res = re.sub(r'\d+', '#', s, count=2)
print(res) # hello# world#
手机号加密 166****6666
s = '16666666666'
res = re.sub(r'(\d{3})\d{4}(\d{4})', r'\1****\2', s)
print(res) # 166****6666
将所有数字反转替换
s = 'hello123 world789'
res = re.sub(r'\d+', lambda x: x.group()[::-1], s)
print(res) # hello321 world987
subn(pattern,repl,string,count,falgs)
返回替换后的结果和替换个数 组成的元组
re.split(pattern,string,maxsplit,flags)
按照pattern拆分,返回拆分后的列表
字符串替换:
replace(old,new,string,count)
old:被替换的子串
new:要替换的字串
count:替换的个数
将所有数字反转替换
s = 'hello123 world789'
res = re.subn(r'\d+', lambda x: x.group()[::-1], s)
print(res) # ('hello321 world987', 2)
flags
flags:正则匹配模式,修饰符
I: 忽略大小写
M: 多行匹配
S: . 将包含(\n) windows换行(\r\n)
res = re.findall('[a-z]+', 'aSD12as', flags=re.I)
print(res) # ['aSD', 'as']
匹配多行开头的数字
res = re.findall(r'^\d+', '123a123\n123wa\n666asd', flags=re.M)
print(res) # ['123', '123', '666']
匹配任意字符 包括换行符\n
res = re.findall('.+', '12 asd \n666 sad', flags=re.S)
print(res) # ['12 asd \n666 sad']
ZIP函数
ls1 = [1, 2, 3, 4, 5, 6, 7]
ls2 = [11, 22, 33, 44, 55]
# 压缩
z = list(zip(ls1, ls2)) # 将两个列表同位压缩
print(z) # [(1, 11), (2, 22), (3, 33), (4, 44), (5, 55)]
# 解压
l = list(zip(*z))
print(l) # [(1, 2, 3, 4, 5), (11, 22, 33, 44, 55)]
'''
abcdefg
1234
a4b3c2d1efg
'''
s1 = 'abcdefg'
s2 = '1234'
z = list(zip(s1, s2[::-1]))
print(z) # [('a', '4'), ('b', '3'), ('c', '2'), ('d', '1')]
s = ''
for i in z:
s += i[0] + i[1]
print(s + s1[len(z):]) # a4b3c2d1efg
'''
[
[('name', '张三'), ('age', 20), ('gender', '男')],
[('name', '李四'), ('age', 30), ('gender', '女')],
[('name', '王五'), ('age', 10), ('gender', '男')]
]
'''
cols = ['name', 'age', 'gender']
data = [
('张三', 20, '男'),
('李四', 30, '女'),
('王五', 10, '男')
]
res = []
for tp in data:
res.append(list(zip(cols, tp)))
print(res) # [[('name', '张三'), ('age', 20), ('gender', '男')], [('name', '李四'), ('age', 30), ('gender', '女')], [('name', '王五'), ('age', 10), ('gender', '男')]]
身份证算法
"""
18位
41072419980815451x
41:省编码前2位
4107:市编码前4位
410724:县编码
451:奇数为男,偶数为女
x:计算所得
1,将前面的身份证号码17位数分别乘以不同的系数。
从第一位到第十七位的系数分别为:7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2;
2,将这17位数字和系数相乘的结果相加;
3,用加出来和除以11,看余数是多少;
4,余数只可能有0,1,2,3,4,5,6,7,8,9,10这11个数字。
分别对应 1,0,x,9,8,7,6,5,4,3,2
"""
from datetime import datetime
import re
# 验证身份证是否合法
# 41072419980815451X
print(re.findall(r'(\d{6})(\d{4})(\d{2})(\d{2})\d{3}([0-9]|X)',
'41072419980815451X')) # [('410724', '1998', '08', '15', 'X')] # [('410724', '1998', '08', '15', 'X')]
def ID(ID):
res = re.findall(r'(\d{6})(\d{4})(\d{2})(\d{2})\d{3}([0-9]|X)', ID)
year = int(res[0][1])
now_year = datetime.now().year
if year > now_year:
# raise Exception('身份证不合法')
print('身份证不合法')
return False
month = int(res[0][2])
if month > 12:
print('身份证不合法')
return False
day = int(res[0][3])
if day > 31:
print('身份证不合法')
return False
last = res[0][4]
ls = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
num = 0
for index, item in enumerate(ls):
num += item * int(ID[index])
mod = num % 11
mods = [1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2]
if str(mods[mod]) != last:
return False
return True
print(ID('41072419980815451X')) # True