正则的用法

正则表达式: 匹配内容,findall()方法将匹配到的内容返回列表,需引入re模块
1.1 匹配单个字符:
import re  # 首先引入re模块
# 匹配单个字符的用法:
# (1) \d:匹配数字
lst = re.findall("\d","字符 1q2we34re6fdsf8dg")
print(lst) # ['1', '2', '3', '4', '6', '8'] 将后面的字符串按照元素拆开,是数字的就放到列表里面
# (2) \D: 匹配非数字
lst = re.findall("\D","23fjs字符")
print(lst) # ['f', 'j', 's', '字', '符']

# (3) \w: 匹配数字字母下滑线和中文
lst = re.findall("\w","27 j3 _d_晴朗")
print(lst) # ['2', '7', 'j', '3', '_', 'd', '_', '晴', '朗']
# (4) \W: 匹配非数字字母下划线中文
lst = re.findall("\W"," 3fs字符 %#")
print(lst) # [' ', ' ', '%', '#']

# (5) \s: 匹配任意空格符 \n,\r,\t
lst = re.findall("\s"," 38s sjf \t  ")
print(lst) # [' ', ' ', ' ', '\t', ' ', ' ']
# (6) \S: 匹配非空格符
lst = re.findall("\S","34sdf 9 \t ")
print(lst) # ['3', '4', 's', 'd', 'f', '9']

# (7) \n: 匹配换行符
str1 = """
换行显示

"""
lst = re.findall("\n",str1)
print(lst) # ['\n', '\n', '\n']

1.2 字符组:  匹配中括号里列举的内容

lst = re.findall("[abc]","oputuopctyauobpt")
print(lst) # ['c', 'a', 'b']

print(re.findall('a[abc]b','aab abb acb adb')) # ['aab', 'abb', 'acb']  # 匹配的数据必须以a开头,以b结尾,

print(re.findall('a[0123456789]b','a1b a2b a3b acb ayb')) # ['a1b', 'a2b', 'a3b']
# 优化: -是一个特殊的字符,代表的是一个范围 0-9 0123456789
print(re.findall('a[0-9]b','a1b a2b a3b acb ayb')) # ['a1b', 'a2b', 'a3b']

print(re.findall('a[abcdefg]b','a1b a2b a3b acb ayb adb')) # ['acb', 'adb']
# 优化: [a-g]  如果想要表达所有的26个小写字母[a-z]
print(re.findall('a[a-g]b','a1b a2b a3b acb ayb adb')) # ['acb', 'adb']

print(re.findall('a[ABCDEFG]b','a1b a2b a3b  aAb aDb aYb')) # ['aAb', 'aDb']
# 优化: [A-G]  如果想要表达所有的26个大写字母[A-Z]
print(re.findall('a[A-G]b','a1b a2b a3b  aAb aDb aYb')) # ['aAb', 'aDb']

print(re.findall('a[0-9a-zA-Z]b','a-b aab aAb aWb aqba1b')) # ['aab', 'aAb', 'aWb', 'aqb', 'a1b']
# 注意: [0-z] 数字 小写 大写 还有特殊字符 比如@ ...
print(re.findall('a[0-z]b','a@b aab aAb aWb aqba1b')) # ['a@b', 'aab', 'aAb', 'aWb', 'aqb', 'a1b']

print(re.findall('a[0-9][*#/]b','a1/b a2b a29b a56b a456b')) # ['a1/b']

1.3 量词: 多个字符的匹配 ?,+,*

# ?: 代表匹配?前面字符的0次或者1次
print(re.findall('a?b','abbzab abb aab')) # ['ab', 'b', 'ab', 'ab', 'b', 'ab']

# +: 代表匹配+前面字符的1次或者多次,就是至少一次
print(re.findall('a+b','b ab aaaaaab abb')) # ['ab', 'aaaaaab', 'ab']

# *:代表匹配*前面字符的0次或者多次,就是任意次
print(re.findall('a*b','b ab aaaaaab abbbbbbb')) # ['b', 'ab', 'aaaaaab', 'ab', 'b', 'b', 'b', 'b', 'b', 'b']

# {m,n}: 匹配m到n次,包含m和n
#  1 <= a <= 3
print(re.findall('a{1,3}b','aaab ab aab abbb aaz aabb')) # ['aaab', 'ab', 'aab', 'ab', 'aab']
# 前面修饰的a , 必须是2个字符
print(re.findall('a{2}b','aaab ab aab abbb aaz aabb')) # ['aab', 'aab', 'aab']
# 前面修饰的a , 至少是2个字符
print(re.findall('a{2,}b','aaab ab aab abbb aaz aabb')) # ['aaab', 'aab', 'aab']

1.4 贪婪模式与非贪婪模式: 一般默认是贪婪模式, 用?在量词后面修饰变成非贪婪模式

                                        贪婪模式: 默认向更多次匹配,底层用回溯算法,走到最后再回头,返回最后一个符合条件的匹配值, 效率比非贪婪模式高

              非贪婪模式:默认匹配更少的次数,用一个?修饰在量词的后面

strvar = "刘能和刘老根和刘铁棍子777子888"
# 贪婪匹配
lst = re.findall("刘.",strvar)
print(lst) # ['刘能', '刘老', '刘铁']

lst = re.findall("刘.?",strvar)
print(lst) # ['刘能', '刘老', '刘铁']

lst = re.findall("刘.+",strvar)
print(lst) # ['刘能和刘老根和刘铁棍子777子888']

lst = re.findall("刘.*",strvar)
print(lst) # ['刘能和刘老根和刘铁棍子777子888']

lst = re.findall("刘.{1,21}",strvar)
print(lst) # ['刘能和刘老根和刘铁棍子777子888']

lst = re.findall("刘.*子",strvar)
print(lst) # ['刘能和刘老根和刘铁棍子777子']

# 非贪婪匹配
lst = re.findall("刘.??",strvar)
print(lst) # ['刘', '刘', '刘']

lst = re.findall("刘.+?",strvar)
print(lst) # ['刘能', '刘老', '刘铁']

lst = re.findall("刘.*?",strvar)
print(lst) # ['刘', '刘', '刘']

lst = re.findall("刘.{1,21}?",strvar)
print(lst) # ['刘能', '刘老', '刘铁']

lst = re.findall("刘.*?子",strvar)
print(lst) # ['刘能和刘老根和刘铁棍子']

lst = re.findall("天??","天空很蓝天气很好")
print(lst) # ['', '', '', '', '', '', '', '', '']  # 代表0次或者1次的非贪婪匹配,所以匹配为空

1.5 特殊字符:  ^, -, \, ., \b, ^, $

# ^ 在字符组当中, 代表除了中括号里的元素,需放到字符组的左边第一个位置
print(re.findall('a[^-+*/]b',"a%b ccaa*bda&bd")) # ['a%b', 'a&b']  除开-+*/这些字符,匹配其余符合条件的

# 如果想要匹配^ 或者 -, 在原来的字符前面加上\,让字符的含义失效.
lst = re.findall(r"e[\^\-]f","e^f e-f")
print(lst) # ['e^f', 'e-f']

# 匹配 \,在斜杠前再加一个斜杠,防止斜杠转义,代表一个斜杠
lst = re.findall(r"a\\c","a\c")
print(lst) # ['a\\c'] 两个斜杠实际代表一个
print(lst[0]) # a\c

# .表示匹配任意字符,除了换行符\n
lst = re.findall(".","w3sf\n")
print(lst) # ['w', '3', 's', 'f']
lst = re.findall(".","33s . s\n")
print(lst) # ['3', '3', 's', ' ', '.', ' ', 's']

# 边界符 \b ^ $
# \b表示卡住字符的开头和结尾,是一个转义字符
strvar = "word pwd scf"
lst = re.findall(r".*d\b",strvar) # 表示元素必须以d结尾
print(lst) # ['word pwd']

lst = re.findall(r".*?d\b",strvar)
print(lst) # ['word', ' pwd']

lst = re.findall(r"\bw",strvar)
print(lst) # ['w']  只匹配w且以w开头

lst = re.findall(r"\bw.*?",strvar)
print(lst) # ['w']

# # 正则表达式中写字符时,要谨慎,下面例子必须匹配到第一个空格时,才结束
lst = re.findall(r"\bw.*? ",strvar)
print(lst) # ['word ']

lst = re.findall(r"\bw\S*",strvar)
print(lst) # ['word']

 # ^ $: ^表示必须以..开头,$表示必须以..结尾.如果字符串中出现^和$,则要把这个字符串当做一个整体来匹配
strvar = "天空天气天气"
print(re.findall('天.',strvar))  # ['天空', '天气', '天气']
print(re.findall('^天.',strvar)) # ['天空']
print(re.findall('天.$',strvar)) # ['天气']
print(re.findall('^天.$',strvar)) # [] 将字符串当做整体来看,没有以.结尾的
print(re.findall('^天.*?$',strvar)) # ['天空天气天气'] 将字符串当做整体来看
print(re.findall('^天.*?天$',strvar)) # []
print(re.findall('^天.*?气$',strvar)) # ['天空天气天气']

print(re.findall('^g.*? ' , 'giveme 1gfive gay')) # ['giveme ']
print(re.findall('five$' , 'aassfive')) # ['five']
print(re.findall('^giveme$' , 'giveme')) # ['giveme']
print(re.findall('^giveme$' , 'giveme giveme')) # []
print(re.findall('giveme' , 'giveme giveme')) # ['giveme', 'giveme']
print(re.findall("^g.*e",'giveme 1gfive gay')) # ['giveme 1gfive']

1.6 匹配分组:  用(),有分组的功能,可以优先显示,用?:表示取消括号里的优先分组

# 要所有的姓名
str1 = 'wusir_good alex_good secret男_good'
print(re.findall("(.*?)_good",str1)) # ['wusir', ' alex', ' secret男']  括号里优先显示
# ?: 不显示括号里面的内容
print(re.findall('(?:.*?)_good','wusir_good alex_good secret男_good'))
 # ['wusir_good', ' alex_good', ' secret男_good']

# |表示或,匹配到|前面或者后面的字符都符合条件,通常都将较难(较长)的条件放|前面,将较易(较短)的条件放|后面
strvar = "abcddd"
lst = re.findall("a|b",strvar)
print(lst) # ['a', 'b']

strvar = "abc24234234ddabcd234234"
lst = re.findall("abc|abcd",strvar)
print(lst)   # ['abc', 'abc']  优先匹配abc,在匹配abcd,所以只匹配到abc
lst = re.findall("abcd|abc",strvar)
print(lst)   # ['abc', 'abcd']  优先匹配abcd,在匹配abc

# (1)匹配小数
strvar = "5.33 3.13 34 34.  .98 9.99 sdfsdf  ......"
lst = re.findall(r"\d+\.\d+",strvar)
print(lst) # ['5.33', '3.13', '9.99']

# (2)匹配小数和整数
strvar = "5.33 3.13 34 34.  .98 9.99 35.5.5sdfsdf  ......"
lst = re.findall(r"\d+(?:\.?\d*)",strvar)
print(lst) # ['5.33', '3.13', '34', '34.', '98', '9.99', '35.5', '5']

# 匹配135或171的手机号
strvar = "asdfasd234 13591199444 17188886666 19145547744"
lst = re.findall("(?:135|171)\d{8}",strvar)
print(lst) # ['13591199444', '17188886666']

# 卡主开头和结尾,数字必须是11位
strvar = "13591199444"
lst = re.findall("^1\d{9}\d$",strvar)
print(lst) # ['13591199444']

2. search函数:  只要找到一个匹配的值就返回,返回的是一个对象,可以把分组内容和匹配内容全部显示出来

         用对象.group()获取匹配的内容, 用对象.groups获取分组的内容


# 匹配www.baidu.com 或者 www.oldboy.com
strvar = "www.baidu.com"
lst = re.findall("^www\.(?:baidu|oldboy)\.com$",strvar)
print(lst) # ['www.baidu.com']

obj = re.search("(www)\.(baidu|oldboy)\.(com)",strvar)
print(obj)  # <_sre.SRE_Match object; span=(0, 13), match='www.baidu.com'>
print(obj.group())  # www.baidu.com
print(obj.groups())  # ('www', 'baidu', 'com')

# 获取第一个小括号里面的内容
print(obj.group(1)) # www
# # 获取第二个小括号里面的内容
print(obj.group(2)) # baidu
# # 获取第三个小括号里面的内容
print(obj.group(3)) # com

# # ### 案例:用正则做运算   "5*6-7/3" 匹配 5*6 或者 7/3
# """search 在匹配不到时,返回的是None,无法使用group"""
# # 匹配出5*6
strvar = "5*6-7/3"
# # 匹配出5*6
obj = re.search(r"\d+[*/]\d+",strvar)
print(obj)
strvar1 = obj.group()
print(strvar1) # 5*6
# 按照*号分隔,算出乘积结果
n1,n2 = strvar1.split("*")
res1 = int(n1)*int(n2)
print(res1)

# 对字符串进行替换
# strvar = "30-7/3"
strvar2 = strvar.replace(strvar1,str(res1))
print(strvar2) # 30-7/3
# 匹配出 7/3
obj = re.search(r"\d+[*/]\d+",strvar2)
strvar3 = obj.group()
print(strvar3) # 7/3
# 按照/号分隔,算出除法结果
n1,n2 = strvar3.split("/")
res2 = int(n1)/int(n2)
print(res2)
# 对字符串进行替换
strvar4 = strvar2.replace(strvar3,str(res2))
print(strvar4)

# 通过-号进行最后的分隔,算出最后的结果.
n1,n2 = strvar4.split("-")
res_finally = float(n1) - float(n2)
print(res_finally)  # 27.666666666666668

2.2 命名分组: 用?P来给匹配条件分组, 后面调用时可以用\1, \2... 也可以用(?P=组名)...

# 分组
strvar = "<div>明天<是>周六</div>"
# 当不清楚字符串中含有什么内容时,用.*?进行取代
lst = re.findall(r"<(.*?)>(.*?)<(.*?)>",strvar)
print(lst) # [('div', '明天', '是')]

# (1) 反向引用: 将第一个括号得到的值,在\1位置处再调用,将第二个括号里得到的值在\2的位置处在调用...
lst = re.findall(r"<(.*?)>(.*?)<(/\1)>",strvar)
print(lst) # [('div', '明天<是>周六', '/div')]

strvar = "a1b2cab"
obj = re.search(r"(.*?)\d(.*?)\dc\1\2",strvar)
print(obj.group()) # a1b2cab

#  (2) 命名分组:用?P给分的小组命名,后面再调用可以继续用\1 \2...,也可以直接用(?P=组名)
# 方法一
strvar = "a1b2cab"
obj = re.search(r"(?P<t1>.*?)\d(?P<t2>.*?)\dc\1\2",strvar)
print(obj.group()) # a1b2cab

# 方法二
strvar = "a1b2cab"
obj = re.search(r"(?P<t1>.*?)\d(?P<t2>.*?)\dc(?P=t1)(?P=t2)",strvar)
print(obj.group()) # a1b2cab
3. match()函数:  用法与search()类似,只是在匹配条件前强制加上^, 强制以...开头, 可用于验证用户输入内容
strvar = "  天空天地"
obj = re.search("天.",strvar)
print(obj.group()) # 天空
obj = re.match("天.",strvar)
print(obj.group()) # 报错,因字符串时空格开头的,不符合match的匹配条件

4. split(): 切割,可根据多种条件进行切割

strvar = "bob-alice&jack%roce-fahai"
res = re.split("[-&%]",strvar)
print(res) # ['bob', 'alice', 'jack', 'roce', 'fahai']

strvar = "0525天气晴朗0524天气多云0523天气阴"
res = re.split("\d+",strvar)
print(res) # ['', '天气晴朗', '天气多云', '天气阴']

5. sub()和subn():  sub()可根据多个条件进行替换,也能选择替换的次数. subn()与sub()用法一样,只是会把新字符串与替换的次数一起组成元祖返回

# sub(): 可根据多个条件进行替换,也能选择替换的次数
strvar = "bob-alice&jack%roce-fahai"
res = re.sub("[-%&]","#",strvar)
print(res) # bob#alice#jack#roce#fahai

res = re.sub("[-%&]","#",strvar,2)
print(res) # bob#alice#jack%roce-fahai  替换两次

# subn(): 与sub()用法一样,只是会把新字符串与替换的次数一起组成元祖返回
strvar = "bob-alice&jack%roce-fahai"
res = re.subn("[-%&]","#",strvar)
print(res) # ('bob#alice#jack#roce#fahai', 4)

strvar = "bob-alice&jack%roce-fahai"
res = re.subn("[-%&]","#",strvar,2)
print(res) # ('bob#alice#jack%roce-fahai', 2)

6.  finditer():  匹配字符串中的内容,返回迭代器,适用于大量数据的匹配

strvar = "0525天气晴朗0524天气多云0523天气阴"
it = re.finditer("\d+",strvar)
obj = next(it)
print(obj.group()) # 0525
obj = next(it)
print(obj.group()) # 0524

strvar = "0525天气晴朗0524天气多云0523天气阴"
it = re.finditer("\d+",strvar)
for i in it:
    print(i.group())
# 0525
# 0524
# 0523

7.  compile():  指定一个统一的匹配规则,可以定义一次匹配规则,终身使用,无需反复定义,节约系统资源

pattern = re.compile("\d+")
strvar = "0525天气晴朗0524天气多云0523天气阴"
res = pattern.findall(strvar)  # 只需传字符串
print(res) # ['0525', '0524', '0523']

str1 = "数学97语文88英语90"
res = pattern.findall(str1)
print(res) # ['97', '88', '90']

obj = pattern.search(str1)
res = obj.group()
print(res) # 97

8. 修饰符: re.I   re.M  re.S

# (1) re.I : 使匹配条件对大小写不敏感
strvar = "<h1>How Are You</H1>"
obj = re.search("<h1>(.*?)</h1>",strvar,flags=re.I)
print(obj.group())

# (2) re.M : 使每一行都可以单独匹配,影响^和$
strvar = """<h1>123</H1>
<p>123</p>
<div>123</div>
"""
res = re.findall("^<.*?>(?:.*?)<.*?>$",strvar)
print(res) # []
res = re.findall("^<.*?>(?:.*?)<.*?>$",strvar,flags=re.M)
print(res) # ['<h1>123</H1>', '<p>123</p>', '<div>123</div>']

# (3) re.S: 匹配包括换行符在内的所有字符
strvar = """give
1112233mefive
"""
pattern = re.compile(".+five")
res = pattern.findall(strvar)
print(res) # ['1112233mefive']
pattern = re.compile(".+five",flags=re.S)
res = pattern.findall(strvar)
print(res) # ['give\n1112233mefive']

 9. 正则案例之正则计算器:

strvar = "1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))"
import re

def sign_exp(strvar):  # 式子的优化
    strvar = strvar.replace("++","+")
    strvar = strvar.replace("--","+")
    strvar = strvar.replace("+-","-")
    strvar = strvar.replace("-+","-")
    return strvar

def calc_exp(strvar):
      # 乘法除法的计算
    if "*" in strvar:
        a, b = strvar.split("*")
        return float(a) * float(b)
    if "/" in strvar:
        a, b = strvar.split("/")
        return float(a) / float(b)

def opreate_exp(strvar):  # (40+5*-2+3/2)
    while True:
        obj =  re.search(r"\d+(\.\d+)?[/*][+-]?\d+(\.\d+)?",strvar)  # 找出式子里第一个乘法或者除法式子
        if obj:
            res1 = obj.group()
            res2 = calc_exp(res1)  # 计算乘法或者除法的结果
            strvar = strvar.replace(res1,str(res2))   # 将结果替换进式子里
        else:
            break
    strvar = sign_exp(strvar)  # 优化式子
    lst = re.findall("[+-]?\d+(?:\.\d+)?",strvar) # 做加减法的累加
    total = 0
    for i in lst:
        total += float(i)
    return total  # 返回结果

def remove_bracket(strvar):  # strvar = "-30+(40+5*-2+3/2)*8+(4-7)"
    while True:
        obj = re.search("\([^()]+\)",strvar)  # 匹配出括号里的式子
        if obj:
            res1 = obj.group()
            # print(res1)  # (40+5*-2+3/2)
            res2 = opreate_exp(res1)   # 做乘除法
            strvar = strvar.replace(res1,str(res2))  # 将乘除法的结果替换进字符串
        else:
            return strvar  # 返回没有括号的字符串

def main(strvar):
    strvar = strvar.replace(" ","")  # 将字符串里空格去掉
    strvar = remove_bracket(strvar)  # 清除小括号
    return opreate_exp(strvar)

res = main(strvar)
print(res)

 

 
posted on 2020-05-22 23:01  fdsimin  阅读(206)  评论(0编辑  收藏  举报