python全栈开发中级班全程笔记(第二模块、第四章(三、re 正则表达式))

时间:2022-08-26 14:57:14

      python全栈开发笔记第二模块

 

第四章 :常用模块(第三部分)

  一、正则表达式的作用与方法

      正则表达式是什么呢?一个问题带来正则表达式的重要性和作用

       有一个需求 : 从文件中读取所有联系人的电话

     1、用传统方式

f = open("re_file", "r")
list_f = []
for date in f.readlines():
name, age, phone, time = date.split(",")
if phone.isdigit():
list_f.append(phone)
print(list_f) # 用这种方式,也取得了其中的电话号码,但是,如果我要取其他东西,就需要重新再写,有点麻烦,

     2、一种新的方法,既简单,又有效,就是标准库的模块(re正则表达式)

import re
f = open("re_file", "r")
date = f.read()
n = re.search("1[0-9]{10}", date) #找到单条符合规则的数据("以几开头[取值范围]{获取数据总长度}", 获取文件内容)
n1 = re.findall("1[0-9]{10}", date) # 找到所有符合条件的数据
print(n, n1)

 二、**重点**常用正则表达式规则

'.'     默认匹配除\n以外的任意一个字符,若指定flag DOTALL,则匹配任意字符包括换行
'^' 匹配字符开头,若指定flags MULTILINE , 这种也可以匹配上(r"^a","\n abc \n asd")
'$' 匹配字符结尾,若指定flags MULTILINE ,re.search('foo.$', 'foo1 \n foo2 \n )
'*' 匹配 * 号前的字符 0 次或多次,re.search('a*','aaavvc') 输出结果为 aaa
'+' 匹配 + 前一个字符一次或多次,re.findall('ab+', "ab+cd+abb+bba") 输出结果为['ab','abba']
'?' 匹配前一个字符 1 次或 0 次,re.search('b?','alex').group() 匹配 0 次
'{m}' 匹配当前一个字符长度为 m 次,re.search('b{3}', 'alexbbbs').group() 匹配到 'bbb'
'{n,m}' 匹配前一个字符长度为 n 到 m 次,re.findall('ab{1,3}','abb abc abbcbbb') 结果‘abb','ab','abb'
'[0-9]' 匹配指定范围 0 到 9 的所有数字范围,也可是 0-5 匹配 5 以内的数字范围
'[a-z]' 匹配指定范围 a 到 z 的所有小写字符,也可为 a-g 匹配 abcdefg 内范围
'|' 匹配 | 左或 | 右的字符,re.search('abc|ABC','ABCBabcCD').group() 结果 'ABC'
'(...)' 分组匹配, re.search("(abc){2}a(123|45)","abcabca456c").groups() 结果 ('abc', '')
实际举例操作
v = "asde12vv33abbaff98aaccd"re.search("...", v) # 默认匹配除\n以外的任意一个或多个字符,(几个点,匹配几个字符)
re.search("^as", v) # 匹配字符开头,如果不设置,会返回空,("^*****")等同于 re.match("as",'asd')
re.search('d$', v) # 匹配字符结尾,如果用在match上面,可以实现精确匹配 match('d$','d')返回d(必须只匹配一个字符)
re.search('ab*', 'aa')# '匹配 * 号前的字符 0 次或多次( 0 次匹配不到也会返回'')(匹配 * 号前首次查找字符的最后为止)
re.findall('a+', 'aaaaab+cd+abb+bba') # 匹配 + 前一个字符一次或多次,('aaaaabbbbbb') 会返回['abbbbbbb']
re.findall('.+', v) # 或和, 联合使用匹配所有字符
re.search("b?", v) # 匹配 ? 前一个字符 1 次或 0 次(最多只能匹配 ? 前字符 1 次)
re.search('b{2}', v) # {指定匹配字符长度},多余只取指定数量,条件不足会返回空(None)
re.findall('[a-c]{1,3}', 'abb abc abbbbab abcdefg') # 匹配前一个字符长度范围{最短字符串n, m最长字符串}
re.search('Will|will', 'will') # (匹配 Will 或者 | 匹配小写 will)
re.search('[w|W]ill', 'Will') # 也可简写成这样 把区分的值写进列表内 [W|w]
re.search('([a-z]+)([0-9]+)', "will678").groups() # 注意语法,分组匹配和 groups() 配合使用才能起效,
re.search("(abc){2}a(123|45)","abcabca456c").groups() # 注意语法和 groups() 的用法

 三、常用表达式(二)

"\A"    只从字符开头匹配,re.search("\Aabc","alexabc")  是匹配不到的,相当于re.match('abc', 'willabc')
"\Z" 匹配字符结尾,同 $
"\d" 匹配数字 0-9 (0到9)'\d' = [0-9], '\d+' = 匹配任意长度的字符,至少1个(常用重点方法)
"\D" 匹配非数字(除数字之外的字符)
"\w" 匹配[A-Za-z0-9] [大写 A 到 Z 所有字符 小写 a 到 z 所有字符 数字 0 到 9 所有数字](常用重点方法)
"\W" 匹配非[A-Za-z0-9] (匹配特殊字符)(除[A-Za-z0-9]外的特殊字符)
"\s" 匹配空白字符( \n \t \r)包括空格,re.search("\s+","ab\t c1\n 3").group() 返回 "\t"
"(?P<name>...)" 分组匹配
re.search('^ab','abd') == re.match('ab', abd) == re.search('\Aab', 'willab')
实际举例操作
v = "asde12vv33abbAAa\nf98aa#$ccd"re.search('\d+', '1455222d8852s')# '\d+' = 匹配任意长度的字符,遇见不符合条件字符终止,
至少能匹配一个(没有数字除外)
re.search('\D+', v) # 匹配非数字(除数字之外的字符)和 \d 相反,遇见不符合条件字符终止
re.search('\w+', v) # 匹配所有 [A-Za-z0-9] 遇见不符合条件字符终止
re.search('\W+', v) # 匹配非[A-Za-z0-9] (特殊字符包含空格)遇见不符合条件字符终止
vr1 = "asde12vv3\t3abbAAa\nf98aa#\r$ccd"re.search('\s+', vr1) # 匹配空白字符( \n \t \r)包括空格,遇见不符合条件字符终止
re.findall('\s+', vr1) # 用 re.findall()语法,相同的方式可匹配所有符合条件的字符
vr2 = '' # 身份证号码
re.search("(?P<province>\d{3})(?P<city>\d{3})(?P<birth>\d{8})(?P<end>\d{4})", vr2).groups()
# 以元祖形式返回(没有命名)目的是把身份证号的地区和生日区分,注意:只要涉及到分组必须用 groups() 语法
re.search("(?P<province>\d{3})(?P<city>\d{3})(?P<birth>\d{8})(?P<end>\d{4})", vr2).groupdict()
# 以字典形式返回并命名

 四、re匹配语法

1、re.match     # 从头开始匹配(只取第一个(或设定)值,如果没有就会返回 None (空)匹配单个)
2、re.search # 匹配包含全局内搜索,匹配到值并返回(只匹配单个值)
3、re.findall # 以列表形式,返回符合条件的所有值
4、re.split # 把匹配到的字符当做列表分隔符
5、re.sub # 匹配字符并替换
6、re.fullmatch # 全部匹配(规则,符合规则的字符)
7、re.compile(pattern,flags=0) # 负责定义规则 re.fullmatch() 的拆解部分,可以配合使用

    1、re.match

re.match()   # 从头开始匹配(只取第一个(或设定)值,如果没有就会返回 None (空)匹配单个)
v = "asde12vv33bff98ccd"
va = re.match("[0-9]", v)

       2、re.search  

re.search()  # 全局内搜索,匹配到值并返回(只匹配单个值)
vb = re.search("[0-9]", v) # 发现返回的是一个对象
if vb: # 先判断返回值不为空(否则会报错)
vr = vb.group() # 再用语法得到返回值
print(vr)
<_sre.SRE_Match object; span=(4, 5), match=''>(span=(值的片位置),match=搜索的值)
print(vb)

   3、re.findall

re.findall()   # 把所有匹配的字符放入列表并返回
vc = re.findall("[0-9]", v)
print(vc)

       4、re.split

vs = re.split()  # 把匹配好的字符当做列表分割符
vs1 = "will25ale#22ja-ck28"
vsa = re.split('\d', vs1) # 发现分开了,却有很多空格的字符串,因为\d 只取一个值
vsb = re.split('\d+', vs1) # \d+ 取多个值,最后一个空字符串因为最后有一个数字被代替
# 语法反转
vsc = re.findall('\d+', vs1) # 发现此语法正好相反,把数字之外的字符当做列表分割符并返回列表内数字值
# 特殊符号分割
vsd = re.split('\d+|#|-', vs1) # 如果字符串内包含多个字符,可以这样分割,空字符串代表数字和分隔符冲突
# 转义和分割结合讲解
vs1 = "will25a|l\e#22|ja-ck28" # 加 2 个 |(管道符)和一个 \(斜杠)
vse = re.split('\|', vs1) # 以管道符分割,需在管道符前添加一个斜杠('\|')
vsf = re.split('\\\\', vs1) # 以斜杠分割,需写 4 个斜杠,("\\\\")
vsfa = re.split('\d+', vs1, maxsplit=2) # maxsplit=要替换几个

     5、re.sub

re.sub()            # 匹配字符并替换,
# 语法:re.sub(pattern,repl,string,count=0,flags=0)
vs1 = "will25al#22ja-ck28"
vsg = re.sub('\d+', '=', vs1, count=2) # (匹配的值,替换的值,字符串, 要替换几个)

     6、re.fullmatch

re.fullmatch(pattern, string, flags=0)    # 全部匹配返回结果,否则返回 None
vsh = re.fullmatch('\w+@\w+\.(com|cn|edu)', "will@yilong.cn") # 匹配邮件为例

     7、re.compile

re.compile()    # 只负责定义规则,re.fullmatch() 的拆解部分,可以配合使用,一个定义一个判断
vsk = re.compile('\w+@\w+\.(com|cn|edu)') # 定义规则
vsm = vsk.fullmatch("will@yilong.cn").group() # 匹配规则
# 和 fullmatch 效果相同(如果一个规则需处理多个内容,用此方法,效率高,减少代码重复)

 五、Flags标志符语法

re.I(re.IGNORECASE) : 忽略大小写(括号内为完整写法,以下相同)
re.M(re.MULTILINE) : 多行模式,改变开头 ^ 和 结尾 $ 的行为,自动识别 \n(换行符)并以行为查找范围
re.S(re.DOTALL) :改变 "." 的行为,不加 S ,换行符不匹配,加了 S ,换行符在内所有都匹配
re.X(re.VERBOSE) : 可以给你的表达式写注释,使其更可读
# 代码实际举例操作
vsn = re.search("a",'Alex', re.I) # 正常情况匹配不上,这样就可以匹配
vso = re.search("wto.$", "wto1\n wto5", re.M)
# 正常情况是匹配后者,但加上 re.M 自动识别 \n(换行符)并以行为查找范围查找前者
vsp = re.search(".", "\n", re.S) # 原本 不匹配换行符,加了re.S ,就可以匹配换行符在内的所有
vsr = re.match("a # 匹配A", "alex", re.X) # 可以在匹配字符内设置注释
vss = re.search("a # 匹配A", "alex") # 如果不加 re.X 会误认为是语法
练习题:
    1、验证手机号是否合法
    2、验证邮箱是否合法
    3、开发一种简单的 python 计算器,实现加减乘除及括号优先级解析
     题为 :js = 1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))
    解题思路:
            1先计算小括号最内部的结果 (用正则式把小括号内的字符串取到)
         2、再计算最后结果,把所有计算的值再用替换的方式换到公式内
         3、用找出标记符号的方法让符号两侧数字计算
# 先写好字体颜色搭配便于调用
def font_color(olo, judge="yes"):
if judge == "yes":
print("\033[33;1m%s\033[0m" % olo)
elif judge == "error":
print("\033[31;1m%s\033[0m" % olo)
# 1、验证手机号是否合法
def user_input():
while True:
phone = input("input phone :")
if phone.isdigit() and len(phone) == 11:
structure = re.search("(?P<dead>\d)(?P<living>\d)(?P<number>\d{9})", phone).groupdict()
if int(structure["dead"]) == 1:
meet = [0, 1, 2, 4]
if int(structure["living"]) in meet:
font_color("is phone number start[13,15,16,17,18,19]", "error")
else:
font_color("very good!!!", "yes")
else:
font_color("phone number is 1 start", "error")
else:
font_color("input 11 digits,not str", "error")
user_input()
# 2、验证邮箱是否合法
def mail_box():
definition = re.compile("\w+@\w+\.(com|cn|net)")
while True:
mail = input("Mailbox account:")
if "@" and "." in mail:
result = definition.fullmatch(mail)
if result:
font_color("very good", "yes")
return font_color(result.group(), "yes")
else:
font_color("mailbox format is [login name@domain name.com \ cn \ net]", "error")
else:
font_color("mailbox format is [login name@domain name.com \ cn \ net]", "error")
mail_box()
# 3、计算题
js = "1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))"
def addition(string):
if "+" in string:
_string = string.split("+")
tote = int(_string[0]) + int(_string[1])
return tote def minus(group):
if "-" in group:
_group = group.split("-")
result = int(_group[0]) - int(_group[1])
return result def ride(array):
if "*" in array:
_array = array.split("*")
sum = int(_array[0]) * int(_array[1])
return sum def divided(block):
if "/" in block:
_block = block.split("/")
gross = int(_block[0]) / int(_block[1])
return gross def inside():
inner = re.findall("\([^()]+\)", js)
ago, big, middle, after = [i.strip("()") for i in inner]
def within():
first = divided(ago)
form_big = re.split("-|\+", big)
one = re.split("/", form_big[1])
res_one = ride(one[0]) / int(one[1])
tow = re.findall("\d+", form_big[2])
tow_ = [int(i) for i in tow]
res_tow = tow_[0] / tow_[1] * tow_[2] / tow_[3] * tow_[4]
three = re.split("/", form_big[3])
res_three = ride(three[0]) / int(three[1])
res_big = first * (int(form_big[0]) - res_one + res_tow + res_three)
return res_big
RES_WIT = within()
middle_res = ride(middle)
after_, afterd = after.split("-")
afterd = ride(afterd)
after_ = int(after_) - afterd
res_ = middle_res / after_
inner_ = re.split("\(|\)", js)
inn_one = inner_[2].split("+")
res_inn_one = minus(inn_one[0])
center = res_inn_one + RES_WIT - res_
rec, rec_ = re.findall("\d+", inner_[0])
res_rec = int(rec_) * center
res_tote = int(rec) - res_rec
print(res_tote)
inside()