第四周Day1 —— Python异常捕获和正则

本文介绍了Python中的异常捕获机制,包括try-except-finally语句的四种形式,强调了finally块的执行特性,并通过实例展示了如何处理可能出现的异常。此外,还详细讲解了正则表达式的概念和常用语法,如匹配类符号、检测类符号、匹配次数、分支和分组以及转义符号,帮助理解正则表达式的强大功能。

Day 15 —— Python异常捕获和正则

一、异常捕获

1. 什么是异常

​ 程序运行的时候报错了,我们程序出现了异常。

程序异常的后果:程序会在异常的地方直接结束,不会往后继续执行。

2. 异常捕获

目的:当程序出现异常的时候,程序不崩溃还可以接着执行后面的代码。

  1. 什么时候需要捕获:

    明明知道某个地方会出现异常,但代码没有问题(用户的不当操作),这个时候就可以使用异常捕获。

  2. 语法:

    • 语法1:捕获所有类型的异常。
    try:
    	代码段1
    except:
    	代码段2
    finally:
    	代码段3
    
    说明:
    try、except - 关键字;固定写法
    代码段1   -   需要捕获异常的代码
    代码段2   -   捕获到异常后会执行的代码
    
    try:
        age = int(input('请输入年龄:'))    # 78a
    except:
        print('年龄有误')
        age = 0
    print(f'年龄是:{age}')                # 年龄有误 年龄是:0
    print('++++++++++++')
    

    执行过程:先执行try后面的代码段1,如果没有异常,直接执行后面的其他代码(不会执行代码段2);

    如果代码段1在执行的时候出现异常,程序不崩溃,直接(马上)执行except后面的代码段2。

    练习:打开指定的文本文件,如果存在就读文件中的内容,如果不存在就创建这个文件。

    try:
        with open('./aaa.txt', 'r', encoding='utf-8') as f:
            f.read()
    except:
        with open('./aaa.txt', 'w', encoding='utf-8') as f:
            f.write('')
    
    • 语法2:捕获指定类型的异常。
    try:
    	代码段1
    except 异常类型:
    	代码段2
    finally:
    	代码段3
    
    try:
        list1 = [10, 20, 30]
        print(list1[3])
        print({'a': 10, 'b': 20}['aa'])
    except IndexError:
        print('出现异常1')
    except KeyError:
        print('出现异常2')
    
    • 语法3:同时捕获多种异常,针对不同的异常进行相同的处理。
    try:
    	代码段1
    except (异常类型1, 异常类型2, ...):
    	代码段2
    finally:
    	代码段3
    
    • 语法4:同时捕获多种异常,针对不同的异常进行不同的处理。
    try:
    	代码段1
    except 异常类型1:
    	代码段11
    except 异常类型2:
    	代码段22
    except 异常类型3:
    	代码段33
    finally:
    	代码段4
    

3. 关键字finally

finally的存在不影响原来异常捕获的执行。

finally后面的代码是不管try里面的代码发生了什么情况都会执行。(就算代码段1出现异常没有被捕获到,finally后面的代码也会执行)。

try:
    print('hello world')
    print('abc'[100])
except IndexError:
    print('出现了异常')
finally:
    print('写遗书')
"""
hello world
出现了异常
写遗书
"""

try:
    print('hello world')
    print({'a': 19}['b'])
except IndexError:
    print('出现了异常')
finally:
    print('写遗书')

"""
hello world
写遗书
KeyError: 'b'
"""

二、正则表达式

1. 什么是正则表达式

​ 正则表达式是让复杂的字符串处理编的更加简单的工具。

2. 正则语法

fullmatch(正则表达式, 字符串)  -  判断指定的字符串是否满足正则表达式描述的规则,如果不满足返回None

python中正则表达式是写到单引号或者双引号里面,例如:'正则表达式'js中正则表达式是放在两个/之间的,例如:/正则表达式/

1. 匹配类符号 (一个符号必须匹配一个对应的字符)
  1. 普通字符

    普通字符值得是正则表达式中除了特殊符号以外的符号都是普通字符。

    普通字符在正则中表示这个符号本身。

    from re import fullmatch
    # 规则:一个字符串有三个字符,第一个字符是a,第二个字符是b,第三个字符是c
    re_str = 'abc'
    result = fullmatch(re_str, 'abc')
    print(result)    # <_sre.SRE_Match object; span=(0, 3), match='abc'>
    
  2. . - 匹配一个任意字符

    # 规则: 一个字符串有三个字符,第一个字符是a,最后一个字符是c,中间是任意字符
    re_str = 'a.c'
    result = fullmatch(re_str, 'ahc')
    print(result)    # <_sre.SRE_Match object; span=(0, 3), match='ahc'>
    

    练习:写一个正则能够匹配一个字符串的开头是1结尾是2,中间两个任意字符

    re_str = '1..2'
    result = fullmatch(re_str, '1不是2')
    print(result)    # <_sre.SRE_Match object; span=(0, 4), match='1不是2'>
    
  3. \d - 匹配一个任意数字

    # 规则:一个字符串有四个字符,第一个字符是a,最后一个字符是b,中间是两个任意数字
    re_str = r'a\d\db'
    result = fullmatch(re_str, 'a12b')
    print(result)    # <_sre.SRE_Match object; span=(0, 4), match='a12b'>
    
  4. \s - 匹配一个任意空白字符

    空白字符:空格、\n\t

    # 规则:一个字符串开头是两个数字,中间一个空白,然后再两个数字
    re_str = r'\d\d\s\d\d'
    result = fullmatch(re_str, '12\n36')
    print(result)    # <_sre.SRE_Match object; span=(0, 5), match='12\n36'>
    
  5. \D - 匹配一个任意非数字字符

    # 规则:一个字符串有四个字符,第一个字符不是数字,后面是abc
    re_str = r'\Dabc'
    result = fullmatch(re_str, 'aabc')
    print(result)   # <_sre.SRE_Match object; span=(0, 4), match='aabc'>
    
  6. \S - 匹配一个任意的非空白字符

    # 规则:一个字符串有5个字符串,第一个字符是数字,第二个字符不是空白字符,后面是abc
    re_str = r'\d\Sabc'
    result = fullmatch(re_str, '12abc')
    print(result)    # <_sre.SRE_Match object; span=(0, 5), match='12abc'>
    
  7. [字符集] - 匹配字符集中任意一个字符

    # [abc你-]   -    能匹配'a'或者'b'或者'c'或者'你'或者'-'
    # [abc\d]   -    能匹配'a'或者'b'或者'c'或者任意一个数字
    # [2-8]    -     能匹配2~8中的任意一个字符
    # [a-z]    -     能匹配a~z中的任意一个字符
    # [A-Z\d]  -      能匹配A~Z中的任意一个字符或者任意一个数字
    # [a-zA-Z]    -   匹配任意一个字母
    # [\u4e00-\u9fa5]   -  匹配任意一个中文
    re_str = r'1[abc]2'
    result = fullmatch(re_str, '1c2')
    print(result)    # <_sre.SRE_Match object; span=(0, 3), match='1c2'>
    

    注意:

    1. 一个[]只能匹配到一个字符

    2. 如果在两个字符之间表示范围,这个-前面的字符的编码值必须小于-后面的字符的编码值

    3. 如果不在两个字符之间,表示-本身

    练习:写一个正则表达式匹配一个字符:123前面是一个数字、字母或者下划线

    re_str = r'[\da-zA-Z_]123'
    result = fullmatch(re_str, '_123')
    print(result)    # <_sre.SRE_Match object; span=(0, 4), match='_123'>
    
  8. [^字符集] - 匹配不在字符集中的任意一个字符

    # [^abc]  -  匹配一个除了'a'、'b'、'c'以外的任意字符
    re_str = r'[^a-zA-Z]'
    result = fullmatch(re_str, 'a')
    print(result)    # None
    result = fullmatch(re_str, 'A')
    print(result)    # None
    result = fullmatch(re_str, '1')
    print(result)    # <_sre.SRE_Match object; span=(0, 1), match='1'>
    
2. 检测类符号

​ 检测符号所在的位置是否符合要求。

注意:检测类的符号不影响匹配。

  1. \b - 检测是否是单词边界

    单词边界:所有可以划分出两个不同单词的符号,包括空白、标点符号、字符串开头或者结尾

    re_str = r'abc\b,123'
    result = fullmatch(re_str, 'abc,123')
    print(result)    # <_sre.SRE_Match object; span=(0, 7), match='abc,123'>
    
  2. \B - 检测是否是非单词边界

    re_str = r'a\B.b'
    result = fullmatch(re_str, 'a4b')
    print(result)   # <_sre.SRE_Match object; span=(0, 3), match='a4b'>
    
  3. ^ - 检测是否是字符串开头

    re_str = r'^\d\d\d'
    result = fullmatch(re_str, '627')
    print(result)    # <_sre.SRE_Match object; span=(0, 3), match='627'>
    
  4. $ - 检测是否是字符串结尾

    re_str = r'\d\d\d$'
    result = fullmatch(re_str, '894')
    print(result)    # <_sre.SRE_Match object; span=(0, 3), match='894'>
    
3. 匹配次数
  1. * - 匹配0次或多次

    re_str = r'1a*2'
    result = fullmatch(re_str, '1aaa2')
    print(result)     # <_sre.SRE_Match object; span=(0, 5), match='1aaa2'>
    
    re_str = r'a\d*b'
    result = fullmatch(re_str, 'a146549879b')
    print(result)     # <_sre.SRE_Match object; span=(0, 11), match='a146549879b'>
    
  2. + - 匹配1次或者多次

    re_str = r'1a+2'
    result = fullmatch(re_str, '1aaa2')
    print(result)
    
    re_str = r'a\d+b'
    result = fullmatch(re_str, 'a146549879b')
    print(result)
    
  3. ? - 匹配0次或1次

    re_str = r'-?\d\d'
    result = fullmatch(re_str, '-23')
    print(result)    # <_sre.SRE_Match object; span=(0, 3), match='-23'>
    
    re_str = r'-?\d\d'
    result = fullmatch(re_str, '--23')
    print(result)    # None
    

练习:写一个正则表达式能够匹配任意整数字符串,包括:8456,+23,-564

re_str = r'[+-]?\d+'
result = fullmatch(re_str, '-6789')
print(result)
  1. {}

    • {N} - 匹配N次
    re_str = r'\d{5}'
    result = fullmatch(re_str, '12345')
    print(result)   # <_sre.SRE_Match object; span=(0, 5), match='12345'>
    
    • {M,N} - 匹配M到N次
    • {M,} - 匹配至少M次
    • {,N} - 匹配最多N次
  2. 贪婪和非贪婪

    在匹配次数不确定的时候匹配模式分为贪婪和非贪婪。

    • 贪婪:在能匹配成功的前提下尽可能多的匹配,例如匹配1次,3次和4次都能匹配成功,最后取4次。
    • 非贪婪:在能匹配成功的前提下尽可能少的匹配,例如匹配1次,3次和4次都能匹配成功,最后取1次。

    默认情况下,所有的不确定次数匹配的时候都是贪婪的:*+?{M,N}{M,}{,N}

    在匹配次数不定的次数后加?,就变成非贪婪模式:*?+???{M,N}?{M,}?{,N}?

    # 贪婪
    re_str = r'a.+b'
    result = search(re_str, '阿傻大姐ashb闪电少女b阿萨德卡')
    print(result)   # <_sre.SRE_Match object; span=(4, 13), match='ashb闪电少女b'>
    # 非贪婪
    re_str = r'a.+?b'
    result = search(re_str, '阿傻大姐ashb闪电少女b阿萨德卡')
    print(result)  # <_sre.SRE_Match object; span=(4, 8), match='ashb'>
    
4. 分支和分组
  1. 分组

    ()将正则的一部分括起来看成一个整体进行操作。

    • 用法一:看成一个整体进行操作
    re_str = r'(\d{2}[a-z]{3}){3}'
    result = fullmatch(re_str, '67adc98fdf48asd')
    print(result)    # <_sre.SRE_Match object; span=(0, 15), match='67adc98fdf48asd'>  
    
    • 用法二:整体重复

      在包含分组的正则中,可以通过\N来重复前面第N个分组匹配到的内容

    re_str = r'a(\d{2})\1'
    result = fullmatch(re_str, 'a8787')
    print(result)   # <_sre.SRE_Match object; span=(0, 5), match='a8787'>
    
    re_str = r'a(\d{2})=\1{2}'
    result = fullmatch(re_str, 'a87=8787')
    print(result)   # <_sre.SRE_Match object; span=(0, 8), match='a87=8787'>
    
    re_str = r'([a-z]+)=(\d{2,4})=\2\1'
    result = fullmatch(re_str, 'ak=879=879ak')
    print(result)   # <_sre.SRE_Match object; span=(0, 12), match='ak=879=879ak'>
    
    • 用法三:捕获

      只针对findall有效。

    re_str = r'tel:(\d{8})'
    result = findall(re_str, 'tel:12345678, name:xiaoming, age=18岁; tel:78946785, name=张三, age=89岁')
    print(result)   # ['12345678', '78946785']
    
  2. 分支 - |

    r'正则表达式1|正则表达式2' -  先用正则1进行匹配,如果失败再使用正则2进行匹配
    
    re_str = r'abc\d{3}|abc[A-Z]{3}'
    # re_str = r'abc(\d{3}|[A-Z]{3})' 与上同义
    result = fullmatch(re_str, 'abc123')
    print(result)   # <_sre.SRE_Match object; span=(0, 6), match='abc123'>
    result = fullmatch(re_str, 'abcADF')
    print(result)   # <_sre.SRE_Match object; span=(0, 6), match='abcADF'>
    
5. 转义符号

​ 正则的转义符号:在具有特殊功能或者特殊意义的符号前加\,让符号原来的功能和意义消失,表示符号本身。

re_str = r'abc\.'
result = fullmatch(re_str, 'abc.')
print(result)   # <_sre.SRE_Match object; span=(0, 4), match='abc.'>

re_str = r'abc[.+?*$^()]'
result = fullmatch(re_str, 'abc.')
print(result)   # <_sre.SRE_Match object; span=(0, 4), match='abc.'>

具有特殊意义和功能的独立的符号,放在[]里面,对应的功能会自动消失,例如:+?*$^(不放在最前面)、|等。

<think>好的,我现在需要帮用户解决如何使用Python正则表达式同时提取身份证号对应的出生年月日的问题。用户之前已经问过如何提取身份证号,现在想进一步同时提取出生日期。我得先回顾之前的回答,确保这次的内容一致并扩展。首先,用户提到的站内引用可能有帮助。引用[1][2]提到正则表达式的基本用法替换,但用户现在需要的是提取,所以可能需要用findall或finditer。引用[3]中的例子用了分组非贪婪匹配,这可能对提取出生日期有用。引用[4]提到多行匹配,但身份证号通常在一行,暂时可能不需要处理换行。接下来,用户的需求是同时提取身份证号对应的出生年月日。之前的正则表达式已经包含了出生日期的部分,所以可以通过分组来捕获年、月、日。例如,在18位身份证号中,第7到14位是出生日期,分解成年(4位)、月(2位)、日(2位)。正则表达式中可以用分组来分别提取这些部分。然后,我需要确保正则表达式正确捕获这些分组。比如,将年份部分(19|20)\d{2}改为捕获组,月份日期同理。这样,匹配的结果会返回包含这些分组的元组,每个元组对应一个身份证号的各个部分。另外,用户可能需要将提取的出生日期格式化为更易读的形式,比如用“年-月-日”格式。这可以通过在正则表达式后处理时拼接分组内容来实现。还要考虑代码示例的清晰性。可能需要使用finditer逐个处理匹配项,并将每个身份证号及其对应的出生日期存储为字典,这样输出更结构化。 同时,需要验证正则表达式是否准确,比如月份日期的范围是否正确,是否排除了无效日期如2月30日。不过,正则表达式可能无法完全处理所有边缘情况,但至少做基本的格式校验。最后,生成相关问题,比如如何验证日期的有效性,如何同时处理15位18位身份证号,如何处理带分隔符的情况等,这些问题可以引导用户进一步学习。</think>### Python正则表达式提取身份证号及出生日期 #### 综合正则表达式设计 ```python import re # 增强版身份证正则表达式(含出生日期捕获组) id_pattern = r"\b([1-9]\d{5})((19|20)\d{2})(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]\b" text = """ 示例文本: 张三32010619800101003X,李四110105199912312349, 无效号123456789012345678,有效号21020320000229001X """ # 使用finditer处理大文本更高效[^2] matches = re.finditer(id_pattern, text) results = [] for match in matches: full_id = match.group(0) year = match.group(2) month = match.group(4) day = match.group(5) birth_date = f"{year}-{month}-{day}" results.append({"身份证号": full_id, "出生日期": birth_date}) print(results) """ 输出: [ {'身份证号': '32010619800101003X', '出生日期': '1980-01-01'}, {'身份证号': '110105199912312349', '出生日期': '1999-12-31'}, {'身份证号': '21020320000229001X', '出生日期': '2000-02-29'} ] """ ``` #### 正则表达式解析 $$ \begin{aligned} & \underbrace{([1-9]\d{5})}_{\text{地址码}} \\ & \underbrace{((19|20)\d{2})}_{\text{年份}} \\ & \underbrace{(0[1-9]|1[0-2])}_{\text{月份}} \\ & \underbrace{(0[1-9]|[12]\d|3[01])}_{\text{日期}} \\ & \underbrace{\d{3}[\dXx]}_{\text{顺序码+校验码}} \end{aligned} $$ 1. **分组捕获**:使用`()`创建捕获组提取地址码、年份、月份、日期[^3] 2. **日期验证**:月份(01-12)日期(01-31)的基本校验 3. **特殊处理**:支持闰年日期如2000-02-29(需额外校验) #### 进阶功能扩展 ```python # 添加日期有效性校验函数 def is_valid_date(year, month, day): try: datetime.datetime(int(year), int(month), int(day)) return True except ValueError: return False # 在循环中添加校验 for match in matches: # ...前略... if is_valid_date(year, month, day): results.append({"身份证号": full_id, "出生日期": birth_date}) ``` #### 处理15位旧版身份证 ```python # 兼容15位身份证的正则表达式 combo_pattern = r"\b([1-9]\d{5})\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}\b|\b([1-9]\d{5})(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]\b" ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值