re模块

re模块

正则表达式就是字符串的匹配规则,在多数编程语言里都有相应的支持,python里对应的模块是re

常用正则表达式规则

'.'     默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行
'^'     匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a","\nabc\neee",flags=re.MULTILINE)
'$'     匹配字符结尾, 若指定flags MULTILINE ,re.search('foo.$','foo1\nfoo2\n',re.MULTILINE).group() 会匹配到foo1
'*'     匹配*号前的字符0次或多次, re.search('a*','aaaabac')  结果'aaaa'
'+'     匹配前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb']
'?'     匹配前一个字符1次或0次 ,re.search('b?','alex').group() 匹配b 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']
'|'     匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 结果'ABC'
'(...)' 分组匹配, re.search("(abc){2}a(123|45)", "abcabca456c").group() 结果为'abcabca45'


'\A'    只从字符开头匹配,re.search("\Aabc","alexabc") 是匹配不到的,相当于re.match('abc',"alexabc") 或^
'\Z'    匹配字符结尾,同$ 
'\d'    匹配数字0-9
'\D'    匹配非数字
'\w'    匹配[A-Za-z0-9]
'\W'    匹配非[A-Za-z0-9]
'\s'     匹配空白字符、\t、\n、\r , re.search("\s+","ab\tc1\n3").group() 结果 '\t'

'(?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'}

例子:

#\W与\w
a="hello 123_12?"
print(re.findall('\W',a))#匹配非字母数字与下划线 打印结果:[' ', '?']
print(re.findall('\w',a))#匹配字母数字与下线划 打印结果:['h', 'e', 'l', 'l', 'o', '1', '2', '3', '_', '1', '2']

#\S与\s
a="hello \t123_12\n"
print(re.findall('\s',a))#匹配任意空字符,等价于[\n\t\r\f]都可以为\s匹配,打印结果:[' ', '\t', '\n']
print(re.findall('\S',a))#匹配任意非空字符 打印结果:['h', 'e', 'l', 'l', 'o', '1', '2', '3', '_', '1', '2']

#\n与\t
print(re.findall(r'\n',"hello\n 123_12\t"))#匹配一个换行符 打印结果:['\n']
print(re.findall(r'\t',"hello \n123_12\t"))#匹配一个制表符 打印结果:['\t']

#\d与\D
print(re.findall('\d','hello 123'))#匹配任意数字,等价[0-9] 打印结果:['1', '2', '3']
print(re.findall('\D','hello,123'))#匹配任意非数字 打印结果:['h', 'e', 'l', 'l', 'o', ',']

#\A与\Z
print(re.findall('\Ahe','hello 123'))#匹配字符串开始位置,相当于^ 打印结果:['he']
print(re.findall('3\Z','hello,123'))#匹配字符串结束位置,相当于$ 打印结果:['3']

#^与$
print(re.findall('^he','hello 123'))#匹配字符串开始位置 打印结果:['he']
print(re.findall('123$','hello,123'))#匹配字符串结束位置 打印结果:['123']

#.匹配任意一个字符,除了换行符
print(re.findall('h.l','hello 123'))#打印结果:['hel']
print(re.findall('a.b','a1b a*b a b aaab'))#打印结果:['a1b', 'a*b', 'a b', 'aab']
print(re.findall('a.b','a1b a*b a\nb aaab'))#打印结果:['a1b', 'a*b', 'aab']

#* 匹配0个或者多个字符
print(re.findall('ab*','bbbbbb'))#打印结果:[]
print(re.findall('ab*','a'))#打印结果:['a']
print(re.findall('ab*','abbbbbbbbb'))#打印结果:['abbbbbbbbb']
#?匹配0个或者1个任意字符
print(re.findall('ab?','a'))#打印结果:['a']
print(re.findall('ab?','abbb'))#打印结果:['ab']
#匹配小数点在内的任意数字
print(re.findall('\d+\.?\d*',"asdfasdf12123.3as1.133342dfa12adsf1asdf3"))#打印结果:['12123.3', '1.133342', '12', '1', '3']

#.* 默认为贪婪匹配
print(re.findall('a.*e','acddedddeb'))#打印结果:['acddeddde']
#.*? 非贪婪匹配
print(re.findall('a.*?e','acddedddeb'))#打印结果:['acdde']

#+ 匹配一个或者多个表达式
print(re.findall('ab+','abbbbbbb1231231'))#['abbbbbbb']

#{n,m} 匹配n到m次
print(re.findall('ab{2}','abbb'))#['abb']
print(re.findall('ab{2,4}','abbb'))#['abbb']
print(re.findall('ab{1,}','abbb'))#['abbb'] 相当于ab+
print(re.findall('ab{0,}','abbb'))#['abbb'] 相当于ab*

#[] 代表或的意思
print(re.findall('a[1*-]b','a1b a*b a-b'))#[]内的都为普通字符了,且如果-没有被转意的话,应该放到[]的开头或结尾
print(re.findall('a[^1*-]b','a1b a*b a-b a=b'))#[]内的^代表的意思是取反,所以结果为['a=b']
print(re.findall('a[^0-9]b','a1b a*b a-b a=b'))#[]内的^代表的意思是取反,所以结果为['a=b']

#\ 转义
# 1 后面加一个元字符使其变成普通符号 \. \*
# 2 将一些普通符号变成特殊符号 比如 \d \w
# print(re.findall('a\\c','a\c'))#对于正则来说a\\c确实可以匹配到a\c,
但是在python解释器读取a\\c时,会发生转义,然后交给re去执行,所以抛出异常
print(re.findall(r'a\\c','a\c'))#r代表告诉解释器使用rawstring,即原生字符串,把我们正则内的所有符号都当普通字符处理,不要转义

#()分组:
print(re.findall('ab+','abababab123'))#['ab', 'ab', 'ab', 'ab']
print(re.findall('(ab)123','ababab123saefqwef')) #['ab'],匹配到末尾的ab123中的ab
print(re.findall('(?:ab)+123','ababab123'))#findall的结果不是匹配的全部内容,而是组内的内容,?:可以让结果为匹配的全部内容
print(re.findall('href="(.*?)"','<a href="http://www.baidu.com">点击</a>'))#['http://www.baidu.com']

#命名分组 格式:?P<"组名">
s2=re.search(r'(?P<author>\w+)\\articles\\(?P<id>\d{7}\.\w+)',r'linhaifeng\articles\6384466.html')
print(s2.group("id"))#6384466.html
print(s2.group("author"))#linhaifeng

#| 或
print(re.findall('www\.(?:baidu|oldboy)\.com','www.baidu.com'))#['www.baidu.com']

re的匹配语法有以下几种

  • re.match 从头开始匹配
  • re.search 匹配包含
  • re.findall 把所有匹配到的字符放到以列表中的元素返回
  • re.split 以匹配到的字符当做列表分隔符
  • re.sub 匹配字符并替换
  • re.fullmatch 全部匹配
    例子:
#re的方法
print(re.findall("\d+",'12312312adfadf'))#匹配所有
#search:只匹配第一个结果
s1=re.search('12','aad1231412')#只到找到第一个匹配然后返回一个包含匹配信息的对象, 该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。
print(s1.group())#['12312312']
#match:只在开始字符进行匹配
s2=re.match('a','aa123121a23a3212a')#None,同search,不过在字符串开始处进行匹配,完全可以用search+^代替match
print(s2.group())#a
#split:分割
print(re.split('1','1231211'))#['', '23', '2', '', ''] 先按1进行分割,得到'','231211',再对'231211'进行割,以此类推
#sub 替换
print(re.sub('\d+','A','hello aadfw1231a312a'))#hello aadfwAaAa 替换所以数字换成A
print(re.sub('\d+','A','hello 123adf3212',2))#hello AadfA 替换两次
#compile:编释方法
a=re.compile("\d+")#定制自己的查询方法
print(a.findall('adfasdf12312adfd1231adf123'))#['12312', '1231', '123']

练习

  • 匹配合法的手机号
import re
def  phone(num):
    '匹配手机号是否合法'
    if  re.findall('^(1\d\d)\d{8}$',num):
        print('%s这是正确的手机号码'%num)
    else:
         print('%s这不是正确的手机号码'%num)
     return (num)

phone('18221212817a')
  • 匹配合法的邮箱
import re
def _email(email):
     '匹配邮箱'
     if re.findall('[\w-]+[.\w-]+@[.\w]+[a-z]{2,3}',email):
         print('%s此邮箱是正确的'%email)
     else:
         print('%s此邮箱是错误的'%email)
_email('www@163.cn')

计算器:

import re

def compute_mul_div(arg):
    '''
    操作乘除
    :param expression:表达式
    :return:计算结果
    1 - 2 * ( (60-30 +(-40.0/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )
    '''
    val=arg[0]
    pattern=re.compile(r'\d+\.*\d*[\*\/]+[\+\-]?\d+\.*\d*')
    # mch=re.search('\d+\.*\d*[\*\/]+[\+\-]?\d+\.*\d*',val)
    mch=pattern.search(val)
    if not mch:
        return
    # content=re.search('\d+\.*\d*[\*\/]+[\+\-]?\d+\.*\d*',val).group()
    content=pattern.search(val).group()

    if len(content.split('*')) >1:
        n1,n2=content.split('*')
        value=float(n1)*float(n2)
    else:
        n1,n2=content.split('/')
        value=float(n1) / float(n2)


    # before,after=re.split('\d+\.*\d*[\*\/]+[\+\-]?\d+\.*\d*',val,1)
    before,after=pattern.split(val,1)
    new_str='%s%s%s' %(before,value,after)
    arg[0]=new_str
    compute_mul_div(arg)

def compute_add_sub(arg):
    '''
    操作加减
    :param expression: 表达式
    :return: 计算结果
    '''
    while True:
        if arg[0].__contains__('+-') or arg[0].__contains__('++') or arg[0].__contains__('-+') or arg[0].__contains__('--'):
            arg[0]=arg[0].replace('+-','-')
            arg[0]=arg[0].replace('++','+')
            arg[0] = arg[0].replace('--', '+')
            arg[0] = arg[0].replace('-+', '-')
        else:
            break

    if arg[0].startswith('-'):
        arg[1] += 1
        arg[0]=arg[0].replace('-','&')
        arg[0] = arg[0].replace('+', '-')
        arg[0] = arg[0].replace('&', '+')
        arg[0]=arg[0][1:]
    val=arg[0]
    pattern=re.compile('\d+\.*\d*[\+\-]{1}\d+\.*\d*')
    # mch=re.search('\d+\.*\d*[\+\-]{1}\d+\.*\d*',val)
    mch=pattern.search(val)
    if not mch:
        return
    content=pattern.search(val).group()
    if len(content.split('+')) >1:
        n1,n2=content.split('+')
        value=float(n1) + float(n2)
    else:
        n1,n2=content.split('-')
        value=float(n1) - float(n2)

    before,after=pattern.split(val,1)
    new_str='%s%s%s' %(before,value,after)
    arg[0]=new_str
    compute_add_sub(arg)

def  compute(expression):
        '''
        操作加减乘除
        :param expression:表达式
        :return:计算结果
        '''
        inp=[expression,0]

        #处理表达式中的乘除
        compute_mul_div(inp)

        #处理
        compute_add_sub(inp)
        if divmod(inp[1],2)[1] == 1:
            result=float(inp[0])
            result=result * - 1
        else:
            result=float(inp[0])
        return  result


def exec_bracket(expression):
    '''
    递归处理括号,并计算
    :param expression: 表达式
    :return: 最终计算结果
    '''
    pattern=re.compile(r'\(([\+\-\*\/]*\d+\.*\d*){2,}\)')
    #如果表达式中已经没有括号,则直接调用负责计算的函数
    if not pattern.search(expression):
        final=compute(expression)
        return final
    #获取第一个只含有 数字/小数 和操作符的括号
    # 如:
    #    ['1-2*((60-30+(-40.0/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))']
    #    找出:(-40.0/5)
    content=pattern.search(expression).group()

    #分割表达式,即:
    # 将['1-2*((60-30+(-40.0/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))']
    # 分割更三部分:['1-2*((60-30+(    (-40.0/5)      *(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))']
    berfore,nothing,after=pattern.split(expression,1)

    print('before',expression)
    content=content[1:len(content)-1]

    # 计算,提取的表示 (-40.0/5),并活的结果,即:-40.0/5=-8.0
    ret=compute(content)

    print('%s=%s' %(content,ret))

    # 将执行结果拼接,['1-2*((60-30+(      -8.0     *(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))']
    expression="%s%s%s" %(berfore,ret,after)
    print('after',expression)
    print('=' *10,'上一次计算结束','='*10)

    # 循环继续下次括号处理操作,本次携带者的是已被处理后的表达式,即:
    # ['1-2*((60-30+   -8.0  *(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))']

    # 如此周而复始的操作,直到表达式中不再含有括号
    return exec_bracket(expression)


# 使用 __name__ 的目的:
#   只有执行 python index.py 时,以下代码才执行
#   如果其他人导入该模块,以下代码不执行
if __name__=='__main__':
    #print '*'*20,"请计算表达式:", "1 - 2 * ( (60-30 +(-40.0/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )" ,'*'*20
    #inpp = '1 - 2 * ( (60-30 +(-40.0/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) ) '

    print("==============================")
    print("\t\t\033[31m欢迎使用计算器\033[0m")
    print("==============================")
    while True:
        inpp=input("请输入表达式:|(退出:q)")
        inpp=re.sub('\s*','',inpp)
        if inpp == "q":
            exit()
        elif re.search('[^0-9\.\-\+\*\/\%\/\/\*\*\(\)]',inpp):
            print("请输入正确的表达式!")
        else:
        #表达式保存在列表中
            result=exec_bracket(inpp)

            print("最后的结果是:\033[31m%s\033[0m" %round(result,2))
posted @ 2018-05-24 17:13  游走在边缘的人  阅读(143)  评论(0编辑  收藏  举报