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

      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', '45')
实际举例操作
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 = '410573199906067745' # 身份证号码 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='1'>(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()
posted @ 2019-04-24 23:20  飝鷬䲍龘  阅读(218)  评论(0编辑  收藏  举报