python学习第18天

一.正则表达式

1.匹配单个字符

import re

lst = re.findall(正则表达式,要匹配的字符串)
返回列表,按照正则表达式匹配到的内容都扔到列表里
最好在正则表达式和要匹配的字符串前面都加上r,原型化输出字符串

1.预定义字符集

  1. \d匹配数字

  2. \D匹配非数字

  3. \w匹配字母或数字或下划线(正则函数中,支持中文的匹配)

  4. \W匹配非字母或数字或下划线

  5. \s匹配任意的空白符(\n \t \r)

  6. \S匹配任意非空白符

  7. \n匹配一个换行符

  8. \t匹配一个制表符

  9. .匹配任意字符,除了换行符\n

2.字符组 必须匹配中括号里列举的字符(默认必须选一个)

lst = re.findall("[abc]","oputuopctyauobpt")
print(lst)

print(re.findall('a[abc]b','aab abb acb adb')) # aab abb acb

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

^ 在字符组当中,代表除了,放到字符组的左边第一个位置

如果想要匹配^或者 - 或者,可在原来的字符前面加上,让字符的含义失效

print(re.findall('a[^-+*/]b',"a%b ccaa*bda&bd")) # a%b a&b
lst = re.findall(r"e[\^\-]f","e^f e-f")

lst = re.findall(r"a\\c","a\c")
print(lst)	#a\\c
print(lst[0])#a\c

\b -> 转义字符 代表退格键backspace

2.匹配多个字符

1.量词练习

  1. ?匹配0个或者一个
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
  1. *匹配0个或者多个
print(re.findall('a*b','b ab aaaaaab abbbbbbb')) # b ab aaaaaab ab b b b b b b
  1. {m,n}匹配m个至n个
# (1) 1 <= x <= 3
print(re.findall('a{1,3}b','aaab ab aab abbb aaz aabb')) # aaab ab aab ab aab
# (2) 前面修饰的a , 必须是2个字符
print(re.findall('a{2}b','aaab ab aab abbb aaz aabb')) # aab aab aab
# (3) 前面修饰的a , 至少是2个字符
print(re.findall('a{2,}b','aaab ab aab abbb aaz aabb')) # aaab aab aab

2.贪婪模式与非贪婪模式

贪婪模式:默认向更多次匹配,底层用的是回溯算法

非贪婪模式:默认向更少次匹配,用一个?号来进行修饰(修饰在量词的身后)

(1)量词( * ? + {} )加上问号?表示非贪婪 惰性匹配
(2)例:.*?w  表示匹配任意长度任意字符遇到一个w就立即停止

回溯算法:从左向右进行匹配,一直到最后,直到最后再也匹配不到了,回头寻找最后一个

. 是匹配任意字符,除了换行符\n

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) # ['刘能和刘老根和刘铁棍子']

3.边界符 \b ^ $

1)\b 本身是一个转义字符 backspace

边界字符 卡单词 word

卡住左边界 \bw

卡住有边界 d\b

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

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

lst = re.findall(r"\bw",strvar)
print(lst) # ['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']^  $
  1. ^ $

^ 必须以..开头

$ 必须以..结尾

如果出现了^ $,要把字符串看成一个整体

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']

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

4.命名分组

1)分组练习(用圆括号),要所有的姓名

print(re.findall('.*?_good','wusir_good alex_good secret男_good'))
# ['wusir_good', ' alex_good', ' secret男_good']

# () 显示括号里面匹配到的内容
print(re.findall('(.*?)_good','wusir_good alex_good secret男_good'))
# ['wusir', ' alex', ' secret男']
# ?: 不优先显示括号里面的内容
print(re.findall('(?:.*?)_good','wusir_good alex_good secret男_good'))
# ['wusir_good', ' alex_good', ' secret男_good']
  1. | 代表或 , a|b 匹配字符a 或者 匹配字符b
# 基本语法
strvar = "abcddd"
lst = re.findall("a|b",strvar) #['a', 'b']
print(lst)
# 注意事项
# 匹配abc 或者 abcd
"""
为了避免优先匹配前面的字符串,导致字符串匹配不完整,
把较难匹配到的字符串写在前面,容易匹配到的字符串放在后面
"""
strvar = "abc24234234ddabcd234234"
# lst = re.findall("abc|abcd",strvar) 注意
# print(lst) # ['abc', 'abc']
lst = re.findall("abcd|abc",strvar)
print(lst) # ["abc","abcd"]

3)练习

.  除了\n,能够匹配到任意字符
\  功效: 让有意义的字符变得无意义,或者让无意义的字符变得有意义
\. 让点原来的特殊含义失效,只是单纯的表达一个点字符.
# (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)匹配小数和整数 
# 整数.小数 34 43234 .
# \d+
# \d+\.\d+ 
lst = re.findall(r"\d+\.\d+|\d+",strvar)
print(lst) # ['5.33', '3.13', '34', '34', '98', '9.99']

用分组形式来做

findall 这个函数优先显示括号里面的内容,
如果不想显示括号内容,使用?:, 显示实际匹配到的内容
lst = re.findall(r"\d+(?:\.\d+)?",strvar)
print(lst) # ['5.33', '3.13', '34', '34', '98', '9.99']
# 匹配135或171的手机号 
strvar = "asdfasd234 13591199444 17188886666 19145547744"
lst = re.findall("(?:135|171)\d{8}",strvar)
print(lst)

# 卡主开头和结尾,数字必须是11位
strvar = "13591199444"
lst = re.findall("^(?:135|171)[0-9]{8}$",strvar)
print(lst)

4)search函数

findall  把所有匹配到的字符串都搜出来,返回列表
       不能把分组内容和匹配的内容同时显示出来
             
search   只要搜索到一个结果就返回,返回对象.
        可以把分组内容和匹配的内容同时显示出来
       
group : 对象.group()  直接获取匹配到的内容
groups: 对象.groups() 直接获取分组里面的内容
# 匹配www.baidu.com 或者 www.oldboy.com
strvar = "www.baidu.com"
lst = re.findall("(?:www)\.(?:baidu|oldboy)\.(?:com)",strvar)
print(lst)

obj = re.search("(www)\.(baidu|oldboy)\.(com)",strvar)
print(obj)
# 获取的是匹配到的数据
print(obj.group())	#www.baidu.com
# 获取的是分组里面的数据
print(obj.groups())	#('www', 'baidu', 'com')
# 获取第一个小括号里面的内容
print(obj.group(1))
# 获取第二个小括号里面的内容
print(obj.group(2))
# 获取第三个小括号里面的内容
print(obj.group(3))

案例

# ### 案例: "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)

当不清楚字符串中含有什么内容的时候,用.*?进行取代

1.反向引用

# \1 代表反向引用,将第一个括号匹配的字符串,在\1位置处在引用一次
lst = re.findall(r"<(.*?)>(.*?)<(/\1)>",strvar)
print(lst)  # [('div', '明天就放假了,很开心', '/div')]

# \1 代表第一个括号  \2代表第二个括号
strvar = "a1b2cab"
obj = re.search(r"(.*?)\d(.*?)\d(.*?)\1\2",strvar)
print(obj)
# 返回匹配到的字符串
res = obj.group()
print(res)
# 返回匹配到的分组内容
res = obj.groups()
print(res)

2.命名分组

"""
# 2.命名分组 (给小组命名)
3) (?P<组名>正则表达式) 给这个组起一个名字
4) (?P=组名) 引用之前组的名字,把该组名匹配到的内容放到当前位置
"""
# 方法一
strvar = "a1b2cab"
obj = re.search(r"(?P<tag1>.*?)\d(?P<tag2>.*?)\d(?P<tag3>.*?)\1\2",strvar)
print(obj.group()) # a1b2cab

# 方法二
strvar = "a1b2cab"
obj = re.search(r"(?P<tag1>.*?)\d(?P<tag2>.*?)\d(?P<tag3>.*?)(?P=tag1)(?P=tag2)",strvar)
print(obj.group()) # a1b2cab

猜你喜欢

转载自www.cnblogs.com/yunchao-520/p/12940407.html