Day 15 —— Python异常捕获和正则
一、异常捕获
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. 匹配类符号 (一个符号必须匹配一个对应的字符)
-
普通字符
普通字符值得是正则表达式中除了特殊符号以外的符号都是普通字符。
普通字符在正则中表示这个符号本身。
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'>
-
.
- 匹配一个任意字符# 规则: 一个字符串有三个字符,第一个字符是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'>
-
\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'>
-
\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'>
-
\D
- 匹配一个任意非数字字符# 规则:一个字符串有四个字符,第一个字符不是数字,后面是abc re_str = r'\Dabc' result = fullmatch(re_str, 'aabc') print(result) # <_sre.SRE_Match object; span=(0, 4), match='aabc'>
-
\S
- 匹配一个任意的非空白字符# 规则:一个字符串有5个字符串,第一个字符是数字,第二个字符不是空白字符,后面是abc re_str = r'\d\Sabc' result = fullmatch(re_str, '12abc') print(result) # <_sre.SRE_Match object; span=(0, 5), match='12abc'>
-
[字符集]
- 匹配字符集中任意一个字符# [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'>
注意:
-
一个
[]
只能匹配到一个字符 -
如果在两个字符之间表示范围,这个
-
前面的字符的编码值必须小于-
后面的字符的编码值 -
如果不在两个字符之间,表示
-
本身
练习:写一个正则表达式匹配一个字符:123前面是一个数字、字母或者下划线
re_str = r'[\da-zA-Z_]123' result = fullmatch(re_str, '_123') print(result) # <_sre.SRE_Match object; span=(0, 4), match='_123'>
-
-
[^字符集]
- 匹配不在字符集中的任意一个字符# [^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. 检测类符号
检测符号所在的位置是否符合要求。
注意:检测类的符号不影响匹配。
-
\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'>
-
\B
- 检测是否是非单词边界re_str = r'a\B.b' result = fullmatch(re_str, 'a4b') print(result) # <_sre.SRE_Match object; span=(0, 3), match='a4b'>
-
^
- 检测是否是字符串开头re_str = r'^\d\d\d' result = fullmatch(re_str, '627') print(result) # <_sre.SRE_Match object; span=(0, 3), match='627'>
-
$
- 检测是否是字符串结尾re_str = r'\d\d\d$' result = fullmatch(re_str, '894') print(result) # <_sre.SRE_Match object; span=(0, 3), match='894'>
3. 匹配次数
-
*
- 匹配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'>
-
+
- 匹配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)
-
?
- 匹配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)
-
{}
{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次
-
贪婪和非贪婪
在匹配次数不确定的时候匹配模式分为贪婪和非贪婪。
- 贪婪:在能匹配成功的前提下尽可能多的匹配,例如匹配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. 分支和分组
-
分组
用
()
将正则的一部分括起来看成一个整体进行操作。- 用法一:看成一个整体进行操作
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']
-
分支 -
|
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.'>
具有特殊意义和功能的独立的符号,放在
[]
里面,对应的功能会自动消失,例如:+
、?
、*
、$
、^
(不放在最前面)、|
等。