【Python】0基础学Python——正则表达式、re模块函数、flags、zip函数、身份证算法

正则表达式

正则

为了匹配一个符合规则的字符串

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值