2. 正则表达式
2.1 概述
学习动机
文本数据处理已经成为常见的编程工作之一
对文本内容的搜索,定位,提取是逻辑比较复杂的工作
为了快速方便的解决上述问题,产生了正则表达式技术
定义
即文本的高级匹配模式,其本质是由一系列字符和特殊符号构成的字串,这个字串即正则表达式。
原理
通过普通字符和有特定含义的字符,来组成字符串,用以描述一定的字符串规则,比如:重复,位置等,来表达某类特定的字符串,进而匹配。
学习目标
熟练掌握正则表达式元字符
能够读懂常用正则表达式,编辑简单的正则规则
能够熟练使用re模块操作正则表达式
2.2 元字符使用
普通字符
匹配规则:每个普通字符匹配其对应的字符
e.g.In : re.findall('ab',"abcdefabcd")Out: ['ab', 'ab']
注意:正则表达式在python中也可以匹配中文
或关系
元字符:|
匹配规则: 匹配 | 两侧任意的正则表达式即可
e.g.In : re.findall('com|cn',"/")Out: ['com', 'cn']In : re.findall("ab|bc","abcabc")Out: ['ab', 'ab']注意:已经匹配过的字符不再重新匹配
匹配单个字符
元字符:.
匹配规则:匹配除换行外的任意一个字符
e.g.In : re.findall('张.丰',"张三丰,张四丰,张五丰")Out: ['张三丰', '张四丰', '张五丰']
匹配字符集
元字符:[字符集]
匹配规则: 匹配字符集中的任意一个字符
表达形式:
[aeiou你我他] 表示 [] 中的任意一个字符 [0-9],[a-z],[A-Z] 表示区间内的任意一个字符 [_#?0-9a-z] 混合书写,一般区间表达写在后面
e.g.In : re.findall('[aeiou]',"How are you!")Out: ['o', 'a', 'e', 'o', 'u']
匹配字符集反集
元字符:[^字符集]
匹配规则:匹配除了字符集以外的任意一个字符
e.g.In : re.findall('[^0-9]',"Use 007 port")Out: ['U', 's', 'e', ' ', ' ', 'p', 'o', 'r', 't']
进入灵魂:与前面的字符搭配出现几次
匹配字符重复
元字符:*
匹配规则:匹配前面的一个字符出现0次或多次(>=1)
e.g.In : re.findall('wo*',"wooooo~~w!")Out: ['wooooo', 'w']
元字符:+
匹配规则: 匹配前面的字符出现1次或多次
e.g.In : re.findall('[A-Z][a-z]+',"Hello World")Out: ['Hello', 'World']
元字符:?
匹配规则: 匹配前面的字符出现0次或1次
e.g. 匹配整数In [28]: re.findall('-?[0-9]+',"Jame,age:18, -26")Out[28]: ['18', '-26']
元字符:{n}
匹配规则: 匹配前面的字符出现n次
e.g. 匹配手机号码In : re.findall('1[0-9]{10}',"Jame:13886495728")Out: ['13886495728']
元字符:{m,n}
匹配规则: 匹配前面的字符出现m-n次
e.g. 匹配qq号In : re.findall('[1-9][0-9]{5,10}',"Baron:1259296994") Out: ['1259296994']
位置匹配开始
匹配字符串开始位置
元字符:^
匹配规则:匹配目标字符串的开头位置(一个字符串只有一个开头或结尾位置)
e.g.In : re.findall('^Jame',"Jame,hello")Out: ['Jame']
匹配字符串的结束位置
元字符:$
匹配规则: 匹配目标字符串的结尾位置
e.g.In : re.findall('Jame$',"Hi,Jame")Out: ['Jame']
规则技巧:
^
和$
必然出现在正则表达式的开头和结尾处。如果两者同时出现,则中间的部分必须匹配整个目标字符串的全部内容。通过正则表达式验证一个密码是否为数字字母下划线构成,并且是 6-12位 In [56]: re.findall('^[ _0-9a-zA-Z]{6,12}$',"tedu_0321") Out[56]: ['tedu_0321']
匹配任意(非)数字字符
元字符:\d(等价于[0-9])
\D (等价于[^0-9])
匹配规则:\d
匹配任意数字字符,\D
匹配任意非数字字符
e.g. 匹配端口In : re.findall('\d{1,5}',"Mysql: 3306, http:80")Out: ['3306', '80']In :re.findall('\D{1,5}',"Mysql: 3306, http:80")Out[35]: ['Mysql', ': ', ', htt', 'p:']
匹配任意(非)普通字符
元字符:\w
\W
匹配规则:\w
匹配普通字符,\W
匹配非普通字符
说明: 普通字符指数字,字母,下划线,汉字,万国字。非普通字符:标点符号,空格等
e.g.In : re.findall('\w+',"server_port = 8888")Out: ['server_port', '8888']In [19]: re.findall('\W+',"server_port = 8888")Out[19]: [' = ']
匹配任意(非)空字符
元字符:\s
\S
匹配规则:\s
匹配空字符,\S
匹配非空字符
说明:空字符指 空格\r \n \t \v \f
字符 其余均是非空字符
e.g.In : re.findall('\w+\s+\w+',"hello world")Out: ['hello world']
匹配(非)单词的边界位置
元字符:\b
\B
匹配规则:\b
表示单词边界,\B
表示非单词边界
说明:单词边界指数字字母(汉字)下划线与其他字符的交界位置。
e.g.In : re.findall(r'\bis\b',"This is a test.") 通过r表达元字符的边界含义,而不是字符串退格含义Out: ['is']
注意: 当元字符符号与Python字符串中转义字符冲突的情况则需要使用r将正则表达式字符串声明为原始功能字符串,如果不确定那些是Python字符串的转义字符,则可以在所有正则表达式前加r。因此实际开发可以无脑加r
2.3 匹配规则
2.3.1 特殊字符匹配
目的 : 如果匹配的目标字符串中包含正则表达式特殊字符,则在表达式中元字符就想表示其本身含义时就需要进行 \ 处理。
特殊字符: . * + ? ^ $ [] () {} | \
操作方法:在正则表达式元字符前加 \ 则元字符就是去其特殊含义,就表示字符本身
e.g. 匹配特殊字符 . 时使用 \. 表示本身含义In : re.findall('-?\d+\.?\d+',"123,-123,1.23,-1.23")Out: ['123', '-123', '1.23', '-1.23']In [4]: re.findall('\$\d+',"日薪: $150")Out[4]: ['$150']
2.3.2 贪婪模式和非贪婪模式
定义 贪婪模式: 默认情况下这个模式,匹配重复的元字符总是尽可能多的向后匹配内容。
比如: * + ? {m,n}
In [40]: re.findall('ab*',"abbbbbbbbbbbbb") Out[40]: ['abbbbbbbbbbbbb']
In [41]: re.findall('ab+',"abbbbbbbbbbbbb") Out[41]: ['abbbbbbbbbbbbb']
In [42]: re.findall('ab?',"abbbbbbbbbbbbb") Out[42]: ['ab']
非贪婪模式: 让匹配重复的元字符尽可能少的向后匹配内容(在符合规则的前提下)
In [42]: re.findall('ab?',"abbbbbbbbbbbbb") Out[42]: ['ab']
In [43]: re.findall('ab*?',"abbbbbbbbbbbbb") Out[43]: ['a']
In [44]: re.findall('ab+?',"abbbbbbbbbbbbb") Out[44]: ['ab']
In [45]: re.findall('ab{2,6}?',"abbbbbbbbbbbbb") Out[45]: ['abb'] In [47]: re.findall('ab{2,}?c',"abbbbbbbbbbbbbc") Out[47]: ['abbbbbbbbbbbbbc']
贪婪模式转换为非贪婪模式(元字符后面加?即可)
In [48]: re.findall('ab.*c',"abbcbbbbbbbbbbbc") Out[48]: ['abbcbbbbbbbbbbbc']
In [49]: re.findall('ab.*?c',"abbcbbbbbbbbbbbc") Out[49]: ['abbc']
在对应的匹配重复的元字符后加 '?' 号即可
* -> *?+ -> +?? -> ??{m,n} -> {m,n}?e.g.In : re.findall(r'\(.+?\)',"(abcd)efgh(higk)")Out: ['(abcd)', '(higk)']
2.3.3 正则表达式分组
定义
在正则表达式中,以()建立正则表达式的内部分组,子组是正则表达式的一部分,作为内部整体操作对象。
In [116]: re.findall("张小亮:(\d+)","王小明:89,张小亮:91,李晓彤:79")Out[116]: ['91']#findall函数特征决定结果只显示符号字符串的子组内容
作用 : 可以被作为整体操作,改变元字符的操作对象
e.g. 改变 +号 重复的对象In : re.search(r'(ab)+',"ababababab").group()Out: 'ababababab'e.g. 改变 |号 操作对象In : re.search(r'(王|李)\w{1,3}',"王者荣耀,李者荣耀").group()Out: '王者荣耀'In [52]: re.findall(r'(王|李)\w{1,3}',"王者荣耀")Out[52]: ['王']
捕获组
捕获组本质也是一个子组,只不过拥有一个名称用以表达该子组的意义,这种有名称的子组即为捕获组。
格式:
(?P<name>pattern)
e.g. 给子组命名为 "pig"In : re.search(r'(?P<pig>ab)+',"ababababab").group('pig')Out: 'ab'功能上相同,只不过给子组起一个名字增加可读性In : re.search(r'ab',"ababababab").group()Out: 'ab'
注意事项
一个正则表达式中可以包含多个子组
子组可以嵌套但是不宜结构过于复杂
子组序列号一般从外到内,从左到右计数
2.3.4 正则表达式匹配原则
正确性,能够正确的匹配出目标字符串.
排他性,除了目标字符串之外尽可能少的匹配其他内容.
全面性,尽可能考虑到目标字符串的所有情况,不遗漏.
可以进行二次程序筛选,在第一次匹配不够精确情况下
2.4 Python re模块使用
2.4.1 基础函数使用
re.findall(pattern,string)功能: 根据正则表达式匹配目标字符串内容参数: pattern 正则表达式string 目标字符串返回值: 匹配到的内容列表,如果正则表达式有子组则只能获取到子组对应的内容,无法获取匹配到的整个串:即使知道整个串符合条件也只给你显示整个串的符合子组条件串。
re.split(pattern,string,max)功能: 使用正则表达式匹配内容,切割目标字符串参数: pattern 正则表达式string 目标字符串max 最多切割几部分返回值: 切割后的内容列表
re.sub(pattern,replace,string,count)功能: 使用一个字符串替换正则表达式匹配到的内容参数: pattern 正则表达式replace 替换的字符串string 目标字符串count 最多替换几处,默认替换全部返回值: 替换后的字符串
"""re 模块示例"""import restr01 = "Alex:1998,Sunny:1999"# 使用正则表达式匹配字符串,将匹配到的内容替换为##,替换2处result = re.sub("\W+","##",str01,2)print(result)# 使用正则表达式匹配的部分分割字符串,分割两处# result = re.split("\W+",str01,2)# print(result)# 如果正则表达式有子组则只能得到子组对应的部分# result = re.findall("(\w+):(\d+)",str01)# print(result)
2.4.2 生成match对象
以上是匹配完字符串直接返回匹配内容,这里匹配的内容不直接给你,通过创建match对象给你返回回来。即在匹配内容同时给你更多信息,例如告诉你在哪个位置匹配上的。
re.finditer(pattern,string)功能: 根据正则表达式匹配目标字符串内容参数: pattern 正则表达式string 目标字符串返回值: 匹配结果的迭代器re.match(pattern,string)功能:匹配某个目标字符串开始位置参数:pattern 正则string 目标字符串返回值:匹配内容match objectre.search(pattern,string)功能:匹配目标字符串第一个符合内容参数:pattern 正则string 目标字符串返回值:匹配内容match object
2.4.3 match对象使用
span() 获取匹配内容的位置(即目标字符串的切片位置)
group(n = 0)
功能:获取match对象匹配内容
参数:默认为0表示获取整个match对象内容,如果是序列号或者组名则表示获取对应子组内容
返回值:匹配字符串
"""正则表达式示例"""import restr01 = "Alex:1998,Sunny:1999"# 只能匹配第一处符合规则内容result = re.search("(\w+):(?P<year>\d+)", str01)print(result.group(1)) # 组编号print(result.group("year")) # 组名#匹配开头位置,相当于自动加上^符号哦result = re.match("\w+",str01)print(result.group())# 返回可迭代对象result = re.finditer("\w+", str01)for item in result:print(item) # match对象 —— 一个match对象对应一处匹配内容print("位置:", item.span())print("内容:", item.group())
"""文件处理综合训练 : 使用提供的inet.log完成设计程序,运行程序后输入 一个接口名称得到这个接口运行情况当中的 address is的值比如:运行程序后输入 BVI100 则得到 10f3.116c.e6a7提示: 要考虑到用户输入的接口不存在的情况每段之间有空行每段的首个单词就是接口名称""""""思路:通过输入,获取所在段落,"""import re# 生成器:每次提供一段内容def every_duan(): # 获取每段内容file = open("inet.log", "r")while True: # 循环一次获取一段内容data = ""for line in file:if line == '\n':breakdata += lineif data:yield dataelse:return Nonedef get_address(port):for data in every_duan():head = re.match("\S+", data).group()if head == port:address = re.search("([0-9a-f]{4}\.?){3}", data)return address.group()return "not found"if __name__ == '__main__':port = input("请输入接口名称")print(get_address(port))
4.txt
前情回顾1. 文件 和 字节串文件 : 文本 二进制字节串 : bytes encode() decode()2. 文件操作open() --> read()/write() -> close()r w a + b3. 缓冲区 文件偏移量缓冲区 : flush() 设置缓冲buffering偏移量 : seek()4. os 模块os.path.getsize()os.listdir()正则表达式匹配训练1. 请在下面字符串中匹配出所有数字今天是 3月30日In [25]: re.findall('[0-9]+','今天是3月30日...: ')Out[25]: ['', '3', '30']2. 使用一个正则表达式匹配一段英文当中所有以大写字母开头的单词In [27]: re.findall('[A-Z][a-z]*',"How are you,Ja...: me")Out[27]: ['How', 'Jame']3. 在下面字符串中匹配数字-12°的气温,战士背着30Kg重装备。In [33]: re.findall('-?[0-9]+',"-12°的气温,战士...: 背着30Kg重装备。")Out[33]: ['-12', '30']4. 匹配国内手机号码In [81]: re.findall(r'\b1[3-9][0-9]{9}\b',"电话:1...: 3838386767,卡号:699915788492384747")Out[81]: ['13838386767']5. 匹配qq号码In [43]: re.findall('[1-9][0-9]{4,10}',"125929699...: 4")Out[43]: ['1259296994']6. 通过正则表达式验证一个密码是否为数字字母下划线构成,并且是 6-12位In [56]: re.findall('^[_0-9a-zA-Z]{6,12}$',"tedu_...: 0321")Out[56]: ['tedu_0321']7. 匹配一组数字 -12 30 1.25 -3.6In [92]: re.findall(r'-?\d+\.?\d*',"-12 30 1.25...: -3.6 5")Out[92]: ['-12', '30', '1.25', '-3.6', '5']8. 匹配 每天薪资日薪: $150In [94]: re.findall(r'\$\d+',"日薪: $150")Out[94]: ['$150']9. 匹配出如下字符串中图书的名字包含书名号张xx :《活着 —— 记录》 《北京, 》李xx :《奥特曼 打小怪兽 ~~ biubiu》王xx :《宇宙危机 @ 叔叔救我》In [111]: re.findall("《.+?》",str01)Out[111]: ['《活着 —— 记录》', '《北京, 》', '《奥特曼 打小怪兽 ~~ biubiu》', '《宇宙危机 @ 叔叔救我》']10. 有一个字符串如下,匹配出张小亮分数王小明:89 ,张小亮:91,李晓彤:79In [116]: re.findall("张小亮:(\d+)","王小明:89...: ,张小亮:91,李晓彤:79")Out[116]: ['91']11. 匹配一个 IP地址ip:192.168.4.45In [125]: re.search(r'(\d{1,3}\.?){4}',"ip:192.16...: 8.4.45").group()Out[125]: '192.168.4.45'12. 匹配身份证号文件处理综合训练 : 使用提供的inet.log完成设计程序,运行程序后输入 一个接口名称得到这个接口运行情况当中的 address is的值比如:运行程序后输入 BVI100 则得到 10f3.116c.e6a7提示: 要考虑到用户输入的接口不存在的情况每段之间有空行每段的首个单词就是接口名称作业: 正则表达式和文件处理总结
"""home022. 编写一个函数,传入一个目录(假设该目录中全是文本文件),函数的功能是将这些文本文件合并为一个大文件,大文件目录是当前路径的下home文件夹下的fileall文件def union_files(dir):pass"""import osdef union_files(dir):fw = open("./home/file_all.txt", 'w')for file in os.listdir(dir):fr = open("./home/" + file, 'r')while True: # 循环边读边写,效率更高data = fr.read(1024)if not data:breakfw.write(data)fr.close()fw.close()union_files("./home")
"""文件存储数据与正则表达式拓展实现"""import re # 导入正则表达式模块import os # 导入操作系统模块filename = "students.txt" # 定义保存学生信息的文件名def menu():# 输出菜单print('''╔———————学生信息管理系统————————╗│ ││ =============== 功能菜单 =============== ││ ││ 1 录入学生信息││ 2 查找学生信息││ 3 删除学生信息││ 4 修改学生信息││ 5 排序 ││ 6 统计学生总人数 ││ 7 显示所有学生信息 ││ 0 退出系统 ││ ========================================== ││ 说明:通过数字键选择菜单│╚———————————————————————╝''')def main():ctrl = True # 标记是否退出系统while ctrl:menu() # 显示菜单option = input("请选择:") # 选择菜单项option_str = re.sub("\D", "", option) # 提取数字if option_str in ['0', '1', '2', '3', '4', '5', '6', '7']:if option_str == '0': # 退出系统print('您已退出学生成绩管理系统!')ctrl = Falseelif option_str == '1': # 录入学生成绩信息insert()elif option_str == '2': # 查找学生成绩信息search()elif option_str == '3': # 删除学生成绩信息delete()elif option_str == '4': # 修改学生成绩信息modify()elif option_str == '5': # 排序sort()elif option_str == '6': # 统计学生总数total()elif option_str == '7': # 显示所有学生信息show()'''1 录入学生信息'''def insert():stdentList = []# 保存学生信息的列表mark = True # 是否继续添加while mark:id = input("请输入ID(如 1001):")if not id: # ID为空,跳出循环breakname = input("请输入名字:")if not name: # 名字为空,跳出循环breaktry:english = int(input("请输入英语成绩:"))python = int(input("请输入Python成绩:"))c = int(input("请输入C语言成绩:"))except:print("输入无效,不是整型数值....重新录入信息")continuestdent = {"id": id, "name": name, "english": english, "python": python, "c": c} # 将输入的学生信息保存到字典stdentList.append(stdent) # 将学生字典添加到列表中inputMark = input("是否继续添加?(y/n):")if inputMark == "y": # 继续添加mark = Trueelse: # 不继续添加mark = Falsesave(stdentList) # 将学生信息保存到文件print("学生信息录入完毕!!!")# 将学生信息保存到文件def save(student):try:students_txt = open(filename, "a") # 以追加模式打开except Exception as e:students_txt = open(filename, "w") # 文件不存在,创建文件并打开for info in student:students_txt.write(str(info) + "\n") # 按行存储,添加换行符students_txt.close() # 关闭文件'''2 查找学生成绩信息'''def search():mark = Truestudent_query = [] # 保存查询结果的学生列表while mark:id = ""name = ""if os.path.exists(filename): # 判断文件是否存在mode = input("按ID查输入1;按姓名查输入2:")if mode == "1":id = input("请输入学生ID:")elif mode == "2":name = input("请输入学生姓名:")else:print("您的输入有误,请重新输入!")continue # 重新查询with open(filename) as file: # 打开文件student = file.readlines() # 读取全部内容for list in student:d = dict(eval(list)) # 字符串转字典if id is not "": # 判断是否按ID查if d['id'] == id:student_query.append(d) # 将找到的学生信息保存到列表中elif name is not "": # 判断是否按姓名查if d['name'] == name:student_query.append(d) # 将找到的学生信息保存到列表中show_student(student_query) # 显示查询结果student_query.clear() # 清空列表inputMark = input("是否继续查询?(y/n):")if inputMark == "y":mark = Trueelse:mark = Falseelse:print("暂未保存数据信息...")return'''3 删除学生成绩信息'''def delete():mark = True # 标记是否循环while mark:studentId = input("请输入要删除的学生ID:")if studentId is not "": # 判断要删除的学生是否存在if os.path.exists(filename): # 判断文件是否存在with open(filename, 'r') as rfile: # 打开文件student_old = rfile.readlines() # 读取全部内容else:student_old = []ifdel = False # 标记是否删除if student_old: # 如果存在学生信息with open(filename, 'w') as wfile: # 以写方式打开文件d = {} # 定义空字典for list in student_old:d = dict(eval(list)) # 字符串转字典if d['id'] != studentId:wfile.write(str(d) + "\n") # 将一条学生信息写入文件else:ifdel = True # 标记已经删除if ifdel:print("ID为 %s 的学生信息已经被删除..." % studentId)else:print("没有找到ID为 %s 的学生信息..." % studentId)else: # 不存在学生信息print("无学生信息...")break # 退出循环show() # 显示全部学生信息inputMark = input("是否继续删除?(y/n):")if inputMark == "y":mark = True # 继续删除else:mark = False # 退出删除学生信息功能'''4 修改学生成绩信息'''def modify():show() # 显示全部学生信息if os.path.exists(filename): # 判断文件是否存在with open(filename, 'r') as rfile: # 打开文件student_old = rfile.readlines() # 读取全部内容else:returnstudentid = input("请输入要修改的学生ID:")with open(filename, "w") as wfile: # 以写模式打开文件for student in student_old:d = dict(eval(student)) # 字符串转字典if d["id"] == studentid: # 是否为要修改的学生print("找到了这名学生,可以修改他的信息!")while True: # 输入要修改的信息try:d["name"] = input("请输入姓名:")d["english"] = int(input("请输入英语成绩:"))d["python"] = int(input("请输入Python成绩:"))d["c"] = int(input("请输入C语言成绩:"))except:print("您的输入有误,请重新输入。")else:break # 跳出循环student = str(d) # 将字典转换为字符串wfile.write(student + "\n") # 将修改的信息写入到文件print("修改成功!")else:wfile.write(student) # 将未修改的信息写入到文件mark = input("是否继续修改其他学生信息?(y/n):")if mark == "y":modify() # 重新执行修改操作'''5 排序'''def sort():show() # 显示全部学生信息if os.path.exists(filename): # 判断文件是否存在with open(filename, 'r') as file: # 打开文件student_old = file.readlines() # 读取全部内容student_new = []for list in student_old:d = dict(eval(list)) # 字符串转字典student_new.append(d) # 将转换后的字典添加到列表中else:returnascORdesc = input("请选择(0升序;1降序):")if ascORdesc == "0": # 按升序排序ascORdescBool = False# 标记变量,为False表示升序排序elif ascORdesc == "1": # 按降序排序ascORdescBool = True# 标记变量,为True表示降序排序else:print("您的输入有误,请重新输入!")sort() mode = input("请选择排序方式(1按英语成绩排序;2按Python成绩排序;3按C语言成绩排序;0按总成绩排序):")if mode == "1": # 按英语成绩排序student_new.sort(key=lambda x: x["english"], reverse=ascORdescBool)elif mode == "2": # 按Python成绩排序student_new.sort(key=lambda x: x["python"], reverse=ascORdescBool)elif mode == "3": # 按C语言成绩排序student_new.sort(key=lambda x: x["c"], reverse=ascORdescBool)elif mode == "0": # 按总成绩排序student_new.sort(key=lambda x: x["english"] + x["python"] + x["c"], reverse=ascORdescBool)else:print("您的输入有误,请重新输入!")sort()show_student(student_new) # 显示排序结果''' 6 统计学生总数'''def total():if os.path.exists(filename): # 判断文件是否存在with open(filename, 'r') as rfile: # 打开文件student_old = rfile.readlines() # 读取全部内容if student_old:print("一共有 %d 名学生!" % len(student_old))else:print("还没有录入学生信息!")else:print("暂未保存数据信息...")''' 7 显示所有学生信息 '''def show():student_new = []if os.path.exists(filename): # 判断文件是否存在with open(filename, 'r') as rfile: # 打开文件student_old = rfile.readlines() # 读取全部内容for list in student_old:student_new.append(eval(list)) # 将找到的学生信息保存到列表中if student_new:show_student(student_new)else:print("暂未保存数据信息...")# 将保存在列表中的学生信息显示出来def show_student(studentList):if not studentList:print("(o@.@o) 无数据信息 (o@.@o) \n")returnformat_title = "{:^6}{:^12}\t{:^8}\t{:^10}\t{:^10}\t{:^10}"print(format_title.format("ID", "名字", "英语成绩", "Python成绩", "C语言成绩", "总成绩"))format_data = "{:^6}{:^12}\t{:^12}\t{:^12}\t{:^12}\t{:^12}"for info in studentList:print(format_data.format(info.get("id"), info.get("name"), str(info.get("english")), str(info.get("python")),str(info.get("c")),str(info.get("english") + info.get("python") + info.get("c")).center(12)))if __name__ == "__main__":main()
Python-Level2-day04:正则表达式概述 元字符使用 匹配规则(特殊字符匹配 贪与非贪婪模式 分组) re模块使用