python,re模块正则

时间:2021-06-10 22:38:17
python没有正则需要导入re模块调用.正则表达式是为了匹配字符串,动态模糊的匹配,只要有返回就匹配到了, 没返回就没匹配到,前面是格式后面是字符串
最常用的匹配语法:
re.match()#麦驰,从头开始匹配(两种方式:简单,分组)
re.search()#色迟,浏览全部字符,匹配第一个符合规则的字符串
re.findall()#把所有匹配到的字符放到以列表中的元素返回
re.split()#以匹配到的字符当做列表分隔符
re.sub()#匹配字符并替换
re.finditer()    

python,re模块正则

python,re模块正则

python,re模块正则

python,re模块正则

扩展:
re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)
M(MULTILINE): 多行模式,改变'^''$'的行为
S(DOTALL): 点任意匹配模式,改变'.'的行为

import re
res=re.match('^zc','zcok168')
print(res)
print(res.group())#打印匹配的内容

'.'     默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行
'^'     匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a","\nabc\neee",flags=re.MULTILINE)
'$'     匹配字符结尾,或e.search("foo$","bfoo\nsdfsf",flags=re.MULTILINE).group()也可
'*'     匹配*号前的字符0次或多次,re.findall("ab*","cabb3abcbbac")  结果为['abb', 'ab', 'a']
'+'     匹配前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb']
'?'     匹配前一个字符1次或0次
'{m}'   匹配前一个字符m次
'{n,m}' 匹配前一个字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 结果'abb', 'ab', 'abb']
'|'    匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 先匹配第一个结果'ABC',如果使用findall就没有group()方法
'(...)' 分组匹配,re.search("(abc){2}a(123|456)c", "abcabca456c").group() 结果 abcabca456c
'\A'    只从字符开头匹配,re.search("\Aabc","alexabc") 是匹配不到的
'\Z'    匹配字符结尾,同$
'\d'    匹配数字0-9
'\D'    匹配非数字的所有字符
'\w'    匹配[A-Za-z0-9]
'\W'    匹配非[A-Za-z0-9]
'\s'    匹配空白字符、\t、\n、\r , re.search("\s+","ab\t\n  \r")结果:'\t\n  \r'>
'(?P<name>...)' 分组匹配 re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})","371481199306143242").groupdict("city")结果: {'province': '3714', 'city': '81', 'birthday': '1993'}

总结:
+ 表示 会按照它前面字符的样式来打印多个
. 表示 打印除\n(换行)外的所有字符
.+ 组合才会全部包括后面的数字 打印之后的所有字符
[a-z] 表示 打印一个小写字母;[A-Z]表示:打印一个大写字母
[a-z] + [A-Z] 可以组合起来用
Eg:("z[a-z]+[A-Z]+","jiang123zhongzHenzhongzhen1232424124zhongzhen")
一、z[a-z]+[A-Z]+.+ 就是将上面从z开始打印完     结果:zhongzHenzhongzhen1232424124zhongzhen
二、"z[a-zA-Z]+\d+" 就是将上面从z开始打印到结果:zhongzHenzhongzhen1232424124
练习例子:
import re
ser=re.search("aal?","aaexaaaa")#匹配问号前面一个字符一次或0次,如果问号前面字符匹配不到会匹配到后面,结果:aa    
print(ser)

ser1=re.search("[0-9]{3}","aa1x2a345aa")#匹配前一个字符M次,结果:345
print(ser1)

ser1=re.findall("[0-9]{1,3}","aa1x2a345aa")#匹配所有字符放到列表中返回,结果:['1', '2', '345']
print(ser1)

ser2=re.search("(abc){2}(\|\|=){2}",'alexabcabc||=||=')#需要\来转义,结果:'abcabc||=||='
print(ser2)
 
ser3=re.search("\A[0-9]+[a-z]\Z","123a")#结果:'123a'
print(ser3)

ser4=re.search("\s+","ab\t\n  \r")#结果:'\t\n  \r'
print(ser4)

ser5=re.search("(?P<id>[0-9]+)(?P<name>[a-zA-Z]+)","abcd1234daf@34").groupdict('name')
print(ser5)#结果:{'id': '1234', 'name': 'daf'}

ser6=re.search("(?P<province>[0-9]{3})(?P<city>[0-9]{3})(?P<birthday>[0-9]{4})","610331198908071513").groupdict()
print(ser6)#分组匹配,{'province': '610', 'city': '331', 'birthday': '1989'}

ser6=re.split("[0-9]+","abc12de3f45GH")
print(ser6)#按数字进行分割,['abc', 'de', 'f', 'GH']

ser7=re.sub("[0-9]+","|","abc12de3f45GH",count=2)#count=2也和写成2
print(ser7)#匹配字符并替换所有数字,加count=2只匹配前2个,abc|de|f45GH

ser8=re.search("[a-z]+","abcdE",flags=re.I)
print(ser8)#大小写都匹配,'abcdE'

重点知识:
res=re.search("aaaaz?","azhangaaaa")# 表示 ?前面的那个 z有和没有都可以  但是z?前面的那些a必须都要匹配到,如果匹配不到就 报错,可以匹配到就输出
res =re.findall("[0-9]{1,3}","z1h23a456n7g8")#re.findall()  没有group方法
print(res)#结果为:['1', '23', '456', '7', '8']
res =re.findall("[0-9]{1,2}","z1h23a456n7g8")
print(res)#结果为:['1', '23', '45', '6', '7', '8']
res =re.findall("[0-9]{3}","z1h23a456n7g8")
rint(res)#结果为:['456']

res=re.search("(?P<province>[0-9]{2})(?P<shi>[0-9]{2})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})","371481199306143242")
print(res.groupdict())   #其中的 ?P 表示语法 <key>[范围]{几位}   结果为:{'province': '37', 'shi': '14', 'city': '81', 'birthday': '1993'}  并且还可以再加几组字典
print(res.groupdict()['city']) #  相当于取出字典中的key=’city’结果为:81
re模块用法案例
res =re.search("[a-z]+","zhangSHuai",flags =re.I)# flag =re.I 忽略大小写  结果为:zhangSHuai
print(res.group())

"""re(正则表达式)就是用于动态匹配的 如果是一个固定值,就不需要通过re来进行    直接通过  wang  in  wangmazi:就可以进行匹配 """

import re
"""re.match 的用法:就是默认从头开始的,
^ 表示要匹配字符开头 故而 ^ 在match中没有用
第一个""写的是要匹配的内容,后面的""写的是匹配度的范围
res =re.match("^wang","wang mazi")
print(res)  #如果有返回结果 就表示匹配到了  如果没有匹配到就返回 None
print(res.group())#通过res.group()来查看匹配到什么"""

""" \d+的用法
\ 表示后面是用于正则的语法,\d表示一个数字 结果为:wang2,
\d+表示一个或多个数字结果为:wang234
res =re.match("wang\d+","wang234 mazi ")
print(res.group())"""

"""   . 的用法
res =re.match(".","@wang234 mazi ")#  . 默认匹配除\n之外的任意一个字符  在此处打印 @
# res =re.match(".+","wang234 mazi ")# + 表示打印后面的多个 故而: .+ 打印全部
# res =re.match(".\d","w1ang234 mazi ")#如果第一位是 w 第二个为数字就可以执行,否则就会报错
# res =re.match("^w","wang234 mazi ")
print(res.group())"""

"""re.serach的用法  表示从整个内容中搜查 这是会用到 ^ 符号"""
#res = re.search("z.+n","jiang123zhongzhen123a")#从z开始 通过.+就z之后一直到
#后面的 n 如果前面+之后没有n就会包括123

#res =re.search("z[a-z]+.+2","jiang123zhong zhen123a")
"""
[a-z]输出一个在a到z之间的一个字符, + 表示多个字符,第一个 + 从o取到g
然后 . 表示一个除\n(换行)外的任意一个字符取出空格, 第二个加号表示
从 z 一直往后取到加号后面的截止字符 结果为:zhong zhen12
res =re.search("z[a-z]+[A-Z]+.+","jiang123zhongzHenzhongzhen1232424124zhongzhen")#输出结果为:zhongZhenzhongzhen
#res =re.search("z[a-zA-Z]+\d+","jiang123zhongzHenzhongzhen1232424124zhongzhen")
res =re.search("#.+#","123#hello#")#结果为:#hello#
print(res.group())"""
# res=re.search("aaaaa?","azhangaaaa")#表示?前面的那个a有和没有都可以 但是a?前面的那些a必须要匹配到
# print(res.group())

"""re.findall() 匹配不相连的多个数字  并且没有group()方法
#res =re.findall("[0-9]{1,2}","z1h23a456n7g8")#结果为:['1', '23', '45', '6', '7', '8']
#res =re.findall("[0-9]{1,3 }","z1h23a456n7g8")#结果为:['1', '23', '456', '7', '8']
res =re.findall("[0-9]{3}","z1h23a456n7g8")#结果为:['456']
print(res)"""

res=re.search("abc|ABC","ABCBabcdB")#先匹配小写或者再匹配大写  返回结果:ABC
res=re.search("abc{2}","abccadf") #匹配abc并且c匹配两次 即:必须要有abcc才可以才返回,否则报错
res =re.search("(abc){2}","abcabcadf")#同上 将abc当做一个小组,同时匹配两次 即:abcabc 否则报错
res =re.search("(abc){2}\|","abcabcadf")#同理 \ 表示转义符,代表不要将 |当做或l来处理 有abcabc| 时才输出,否则报错
res =re.search("(abc){2}(\|\|=){2}","sdabcabc||=||=adf")# 每一个 \| 都要用输出结果为:abcabc||=||=
res =re.search("\A[0-9]+[a-z]+\Z","123sdf")#\A等同于 ^ ,表示从第一个元素开始,从第一个为数字,然后经过几个数,然后经过几个字母\Z表示以 字母结束
res =re.search("\D+","123&%*- A@ \\n") #\D匹配不是数字的任意一个字符  特殊字符可以 换行也可以 结果为:&%*- A@ \n
res =re.search("\w+","123&%*- A@ \\n")# 小写的 \w只匹配数字和字母 结果为:123
res =re.search("\W+","123&%*- A@ \\n")#只匹配特殊字符 结果为:&%*-
#res =re.search("\s+","\r\t\n123&%*- A@ ")
res=re.search("(?P<province>[0-9]{2})(?P<shi>[0-9]{2})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})","371481199306143242")
#其中的 ?P 表示语法 <key>[范围]{几位}   结果为:{'province': '37', 'shi': '14', 'city': '81', 'birthday': '1993'}
print(res.groupdict()['city'])
res =re.split("[0-9]+","ab2h4h35g42g") # 因为[0-9]只是一个字符,故而表示将后面的内容# 以数字分隔开,然后是单个数字的去掉,
多个数字的就以空字符显示出来并与分隔开的字母形成列表   结果为:['ab', 'h', 'h', '', 'g', '', 'g']
res =re.sub("[0-9]+","|","ab2h4h35g42g",count=2)
print(res)
res =re.search("[a-z]+","zhangSHuai",flags =re.I)# flag =re.I 忽略大小写  结果为:zhangSHuai
print(res.group())
计算器作业
1.    实现加减乘除及拓号优先级解析
2.    用户输入 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )等类似公式后,必须自己解析里面的(),+,-,*,/符号和公式(不能调用eval等类似功能偷懒实现),运算后得出结果,结果必须与真实的计算器所得出的结果一致
3.    import re
import functools
def minus_operator_handler(formula):
    '''处理一些特殊的减号运算'''
    minus_operators = re.split("-", formula)
    calc_list = re.findall("[0-9]", formula)
    if minus_operators[0] == '':  # 第一值肯定是负号
        calc_list[0] = '-%s' % calc_list[0]
    res = functools.reduce(lambda x, y: float(x) - float(y), calc_list)
    print("\033[33;1m减号[%s]处理结果:\033[0m" % formula, res)
    return res

def remove_duplicates(formula):
    formula = formula.replace("++", "+")
    formula = formula.replace("+-", "-")
    formula = formula.replace("-+", "-")
    formula = formula.replace("--", "+")
    formula = formula.replace("- -", "+")
    return formula

def compute_mutiply_and_dividend(formula):
    '''算乘除,传进来的是字符串噢'''
    operators = re.findall("[*/]", formula)
    calc_list = re.split("[*/]", formula)
    res = None
    for index, i in enumerate(calc_list):
        if res:
            if operators[index - 1] == "*":
                res *= float(i)
            elif operators[index - 1] == "/":
                res /= float(i)
        else:
            res = float(i)

    print("\033[31;1m[%s]运算结果=\033[0m" % formula, res)
    return res

def handle_minus_in_list(operator_list, calc_list):
    '''有的时候把算术符和值分开后,会出现这种情况  ['-', '-', '-'] [' ', '14969037.996825399 ', ' ', '12.0/ 10.0 ']
       这需要把第2个列表中的空格都变成负号并与其后面的值拼起来,恶心死了
    '''
    for index, i in enumerate(calc_list):
        if i == '':  # 它其实是代表负号,改成负号
            calc_list[index + 1] = i + calc_list[index + 1].strip()

def handle_special_occactions(plus_and_minus_operators, multiply_and_dividend):
    '''有时会出现这种情况 , ['-', '-'] ['1 ', ' 2 * ', '14969036.7968254'],2*...后面这段实际是 2*-14969036.7968254,需要特别处理下,太恶心了'''
    for index, i in enumerate(multiply_and_dividend):
        i = i.strip()
        if i.endswith("*") or i.endswith("/"):
            multiply_and_dividend[index] = multiply_and_dividend[index] + plus_and_minus_operators[index] + \
                                           multiply_and_dividend[index + 1]
            del multiply_and_dividend[index + 1]
            del plus_and_minus_operators[index]
    return plus_and_minus_operators, multiply_and_dividend

def compute(formula):
    '''这里计算是的不带括号的公式'''

    formula = formula.strip("()")  # 去除外面包的拓号
    formula = remove_duplicates(formula)  # 去除外重复的+-号
    plus_and_minus_operators = re.findall("[+-]", formula)
    multiply_and_dividend = re.split("[+-]", formula)  # 取出乘除公式
    if len(multiply_and_dividend[0].strip()) == 0:  # 代表这肯定是个减号
        multiply_and_dividend[1] = plus_and_minus_operators[0] + multiply_and_dividend[1]
        del multiply_and_dividend[0]
        del plus_and_minus_operators[0]

    plus_and_minus_operators, multiply_and_dividend = handle_special_occactions(plus_and_minus_operators,
                                                                                multiply_and_dividend)
    for index, i in enumerate(multiply_and_dividend):
        if re.search("[*/]", i):
            sub_res = compute_mutiply_and_dividend(i)
            multiply_and_dividend[index] = sub_res
    # 开始运算+,-
    print(multiply_and_dividend, plus_and_minus_operators)
    total_res = None
    for index, item in enumerate(multiply_and_dividend):
        if total_res:  # 代表不是第一次循环
            if plus_and_minus_operators[index - 1] == '+':
                total_res += float(item)
            elif plus_and_minus_operators[index - 1] == '-':
                total_res -= float(item)
        else:
            total_res = float(item)
    print("\033[32;1m[%s]运算结果:\033[0m" % formula, total_res)
    return total_res

def calc(formula):
    '''计算程序主入口, 主要逻辑是先计算拓号里的值,算出来后再算乘除,再算加减'''
    parenthesise_flag = True
    calc_res = None  # 初始化运算结果为None,还没开始运算呢,当然为None啦
    while parenthesise_flag:
        m = re.search("\([^()]*\)", formula)  # 找到最里层的拓号
        if m:
            # print("先算拓号里的值:",m.group())
            sub_res = compute(m.group())
            formula = formula.replace(m.group(), str(sub_res))
        else:
            print('\033[41;1m----没拓号了...---\033[0m')

            print('\n\n\033[42;1m最终结果:\033[0m', compute(formula))
            parenthesise_flag = False  # 代表公式里的拓号已经都被剥除啦

if __name__ == '__main__':
    # res = calc("1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )")
    res = calc(
        "1 - 2 * ( (60-30 +(-9-2-5-2*3-5/3-40*4/2-3/5+6*3) * (-9-2-5-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )")