欢迎来到十九分快乐的博客

生死看淡,不服就干。

17.正则表达式

正则表达式

1.什么是正则表达式

"""
定义:
    用来约束字符串匹配某种形式的规则
作用;
    1.检测某个字符串是否符合规则;(手机号,身份证号是否合法)
    2.提取网页字符串中想要的数据.(爬虫中提取天气,幸运的信息)
    在线测试工具  http://tool.chinaz.com/regex/
组成: 普通字符和元字符组成
    1.普通字符串: 大小写字母和数字
    2.元字符具有特殊含义,大体种类分为:
        (1)预定义字符集,字符组
        (2)量词
        (3)边界符
        (4)分组   
函数:需要导入import re 模块
	findall("正则表达式","字符串") 从左到右匹配,找到所有的内容,返回列表
	search("正则表达式","字符串")  从左到右匹配,匹配到第一个满足条件的内容直接返回,返回的是对象
"""

2.匹配单个字符 : 预定义字符集和字符组

import re

"""
语法:re.findall("正则表达式","字符串") 返回列表
注意:正则表达式前面加r防止转义,一定不会错
"""
# 1.预定义字符集
# . 匹配任意字符,除了换行符\n
print(re.findall(".","3a\rd"))  #['3', 'a', '\r', 'd']

# \d 匹配数字
# \D 匹配非数字
print(re.findall("\d","sd3kj4")) #['3', '4']
print(re.findall("\D","sd3kj4")) #['s', 'd', 'k', 'j']

# \w 匹配字母数字下划线和中文
# \W 匹配非字母数字下划线和中文
print(re.findall("\w","f2_健康*&")) #['f', '2', '_', '健', '康']
print(re.findall("\W","f2_健康*&")) #['*', '&']

# \s 匹配任意的空白符(空格,\r,\t,\n 等)
# \S 匹配任意非空白符
print(re.findall("\s","k d \rd")) #[' ', ' ', '\r']
print(re.findall("\S","k d \rd")) #['k', 'd', 'd']

# \n 匹配换行符
# \t 匹配制表符
strvar = """
11122			3434
"""
print(re.findall(r"\n",strvar)) #['\n', '\n']
print(re.findall(r"\t",strvar)) #['\t', '\t', '\t']

# 2.字符组 默认必须从字符组中选一个
"""
[...]  匹配字符组中的字符
[^..] 匹配非字符组中的字符(^必须写在第一位)
[0-9] 表示 0~9 所有数字
[a-z] 表示所有小写字母
[A-Z] 表示所有大写字母
[0-9a-zA-Z] 表示所有字母数字,该正则可验证十六进制 
[\u4e00-\u9fa5] 表示匹配所有汉字
"""
print(re.findall("[12]","d2k43jl1")) #['2', '1']
print(re.findall('a[0-9]b','a1b a2b a3b acb ayb')) #['a1b', 'a2b', 'a3b']
print(re.findall('a[0-9][*#/]b','a1/b a2b a29b '))#['a1/b']

# 3.匹配转义字符
"""
需要(\)进行转义
而且正则表达式和后面字符串都需要加r
"""
# (1)匹配^ - \ 特殊字符 
strvar1 = "a^n a-n a\n" 
strvar2 = r"a^n a-n a\n"  #加r防止转义
print(re.findall(r"a[\^\-\\]n",strvar1)) #['a^n', 'a-n']
print(re.findall(r"a[\^\-\\]n",strvar2)) #['a^n', 'a-n', 'a\\n']

# (2)匹配\b
strvar=r"aed\bkja\b lka\b"
print(re.findall(r"a\\b",strvar))#['a\\b', 'a\\b']

3.多个字符匹配 : 量词

# 1.量词
"""
? : 匹配 0~1 个
+: 匹配 1~+∞ 个
* : 匹配 0~+∞ 即任意个
{n} 匹配n 个
{n,m} 匹配 n~m 个
{n,} 匹配 n~+∞
"""
print(re.findall("a?b","baabab abb")) #['b', 'ab', 'ab', 'ab', 'b']
print(re.findall("a+b","baabab abb")) #['aab', 'ab', 'ab']
print(re.findall("a*b","baabab abb")) #['b', 'aab', 'ab', 'ab', 'b']
print(re.findall("a{2}b","baabab abb")) #['aab']
print(re.findall("a{1,3}b","baabab abb")) #['aab', 'ab', 'ab']
print(re.findall("a{1,}b","baabab abb")) #['aab', 'ab', 'ab']

# 2.贪婪匹配和非贪婪匹配
"""
贪婪模式 :默认向更多次匹配
    回溯算法 : 从左向右一直匹配,直到匹配不到了,在回头,把上一次找到的元素返回
非贪婪模式: 默认向更少次匹配
    语法:量词 + "?"
    例:.*?w  表示匹配任意长度任意字符遇到一个w就立即停止
"""
strvar="刘能和刘老根和刘一手1子2子"
print(re.findall("刘.?",strvar)) #['刘能', '刘老', '刘一']
print(re.findall("刘.??",strvar))#['刘', '刘', '刘']
print(re.findall("刘.+",strvar)) #['刘能和刘老根和刘一手1子2子']
print(re.findall("刘.+?",strvar))#['刘能', '刘老', '刘一']
print(re.findall("刘.*子",strvar)) #['刘能和刘老根和刘一手1子2子']
print(re.findall("刘.*?子",strvar))#['刘能和刘老根和刘一手1子']

# 3.匹配开头结尾->边界符
"""
只要不是字母数字下划线都可以作为边界
边界符\b : 
    1.\b 可以作为转义字符 ->退格
    2.\b 正则中的边界符
    例如:word  卡住左边界\bw ,卡主右边界 d\b
    注意:正则表达式前需要加r 防止转义
    
^ :匹配字符串的开始
$ :匹配字符串的结尾
    如果使用了^ 和 $ 必须要把字符串看成一个整体
"""
strvar = "word pwd wook"
# 卡住左边界
print(re.findall(r"\bw",strvar))#['w', 'w']
print(re.findall(r"\bp",strvar))#['p']
print(re.findall(r"\bw.*",strvar))#['word pwd wook']
print(re.findall(r"\bw.*?",strvar))#['w', 'w']
print(re.findall(r"\bw\S*",strvar))#['word', 'wook']

# 卡主右边界
print(re.findall(r"d\b",strvar))#['d', 'd']
print(re.findall(r".*d\b",strvar))#['word pwd']
print(re.findall(r".*?d\b",strvar))#['word', ' pwd']

# ^ 匹配字符串的开始  $匹配字符串的结尾
print(re.findall("^w.*",strvar))#['word pwd wook']
print(re.findall("^w.*?",strvar))#['w']
print(re.findall("k$",strvar)) #['k']
print(re.findall(".*k$",strvar))#['word pwd wook']
print(re.findall(".*?k$",strvar))#['word pwd wook']从左到右匹配,结尾结束

4.匹配分组

import re

# 1.匹配分组()表示一个整体
"""
(正则表达式):优先显示括号里的内容
(?:正则表达式):取消优先显示
"""
print(re.findall(".*?_d","jia_d ying_d he_d")) #['jia_d', ' ying_d', ' he_d']
print(re.findall("(.*?)_d","jia_d ying_d he_d"))#['jia', ' ying', ' he']
print(re.findall("(?:.*?)_d","jia_d ying_d he_d"))#['jia_d', ' ying_d', ' he_d']

# 2.| 或
"""
注意:
    把较难匹配的内容放到前面,容易匹配的放到后面,才能保证所有元素都可以匹配到
"""
print(re.findall("ab|abc","sabcdfabdabc"))#['ab', 'ab', 'ab']
print(re.findall("abc|ab","sabcdfabdabc"))#['abc', 'ab', 'abc']

strvar="2.3 22 33. ..44 66.66 77"
# 匹配小数
print(re.findall("\d+\.\d+",strvar))#['2.3', '66.66']
# 匹配整数(取值不正确)
print(re.findall("\d+",strvar)) #['2', '3', '22', '33', '44', '66', '66', '77']
# 匹配小数和整数
print(re.findall("\d+\.\d+|\d+",strvar))#['2.3', '22', '33', '44', '66.66', '77']
# 使用分组的形式匹配小数和整数
print(re.findall("\d+(?:\.\d+)?",strvar))#['2.3', '22', '33', '44', '66.66', '77']

# 匹配135或137的手机号
strvar="13546346454 13640393839 13728394583"
print(re.findall("(?:135|137)\d{8}",strvar))#['13546346454', '13728394583']
# 只匹配一个手机号
strvar="13593849384"
print(re.findall("^(?:135|137)\d{8}$",strvar))#['13593849384']

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

# 3.反向引用:\n引用前面第n个分组匹配到的内容
strvar="<abs>dk3<abs>"
# 把第一个括号里面的数据放到\1引用
obj=re.search(r"<(.*?)>(.*?)<\1>",strvar)
print(obj.group())#获取匹配到的数据
print(obj.groups())#获取分组里面的内容

#4.命名分组
"""
(?P<组名>正则表达式) 给分组起一个名字
(?P=组名) 引用组名,把该组名匹配到的数据放到当前位置
"""
obj=re.search(r"<(?P<tag1>.*?)>(?P<tag2>.*?)<(?P=tag1)>",strvar)
print(obj.group()) #<abs>dk3<abs>
print(obj.groups()) #('abs', 'dk3')

# 4.search函数和findall的区别
"""
findall  :  优点:从左到右匹配,找到所有的内容,返回列表
			缺点:匹配的内容和分组的内容不能同时显示在同一个界面中
			
search   :  缺点:从左到右匹配,匹配到第一个满足条件的内容直接返回,返回的是对象
			优点:可以把分组里的内容和匹配到的内容同时显示在同一个界面中

obj.group()  => 获取匹配到的内容
obj.groups() => 获取分组中的内容
"""
obj=re.search("(www)\.(baidu|oldboy)\.(com)",strvar)
print(obj)  #返回对象
print(obj.group()) #www.baidu.com
print(obj.groups()) #('www', 'baidu', 'com')

5.正则函数

# 1.findall 匹配字符串相应内容, 返回列表
"""
findall ("正则表达式","字符串")
"""
strvar="sdf23sd"
print(re.findall("\d",strvar)) #['2', '3']

# 2.search 匹配出第一个符合条件的数据返回,返回对象
obj=re.search("\d",strvar)
print(obj.group()) #2

# 3.match 验证用户输入内容
"""
与search使用方法一样,search正则表达式开头加^(以..开头),等价于match
"""

# 4.split ("正则表达式","字符串") 按正则表达式把字符串切割成列表
strvar="aa|bb&cc*dd_ee"
print(re.split("[|&*_]",strvar))#['aa', 'bb', 'cc', 'dd', 'ee']
strvar="aa343bb33214cc"
print(re.split("\d+",strvar)) #['aa', 'bb', 'cc']

# 5.sub 替换 返回被替换的字符串
"""
sub("正则表达式","替换的元素","原字符串",替换次数)
"""
strvar="aa|bb&cc*dd_ee"
print(re.sub("[|*&_]","@",strvar)) #aa@bb@cc@dd@ee
print(re.sub("[|*&_]","@",strvar,2)) #aa@bb@cc*dd_ee

# 6.subn 替换  与sub一样 返回元组
"""
sub("正则表达式","替换的元素","原字符串",替换次数)
返回 : ("被替换的字符串",替换次数)
"""
print(re.subn("[|*&_]","@",strvar,2)) #('aa@bb@cc*dd_ee', 2)

# 7.finditer 匹配字符串中相应内容,返回迭代器
strvar="s234sf"
it=re.finditer("\d",strvar)
print(it) #<callable_iterator object at 0x7f21f3c536a0>
print(next(it)) #<_sre.SRE_Match object; span=(1, 2), match='2'>
"""迭代器里面是类似search对象,需要用group获取内容"""
print(next(it).group()) #3
it=re.finditer("\d",strvar) #重置迭代器
for i in it:
    print(i.group())

# 8.compile ("正则表达式")制定一个统一的匹配规则
"""
compile("正则表达式",flags=修饰符) flags默认为0
修饰符:
    1.re.I(大写i)    使匹配对大小写不敏感
    2.re.M  使每一行都能够单独匹配(多行匹配),影响^和$
    3.re.S    使 . 匹配包括换行在内的所有字符
作用:制定一次正则表达式,重复使用,提高执行效率
"""
pattern=re.compile("\d") #制定匹配规则
print(pattern) #re.compile('\\d')
# 使用规则
strvar="ad334j"
print(pattern.findall(strvar)) #['3', '3', '4']
obj=pattern.search(strvar)
print(obj.group()) #3

# 修饰符
# 1.re.I    使匹配对大小写不敏感
strvar="<a>都会尽快</A>"
pattern=re.compile("<a>(.*?)</a>",flags=re.I)
obj=pattern.search(strvar)
print(obj.group())

# 2.re.M  使每一行都能够单独匹配,影响^和$
strvar = """
<a>我是连接</a>
<p>我是段落</p>
<div>我是盒子</div>
"""
pattern=re.compile("^<.*?>.*?<.*?>$",flags=re.M)
print(pattern.findall(strvar))#['<a>我是连接</a>', '<p>我是段落</p>', '<div>我是盒子</div>']

# 3.re.S    使 . 匹配包括换行在内的所有字符
strvar="""
dskfl jdfks
fdj3423me
"""
pattern=re.compile(".*?me",flags=re.S)
obj=pattern.search(strvar)
print(obj.group()) #字符串所有内容,包括换行

# 想要所有修饰符,使用|进行拼接
pattern=re.compile(".*?me",flags=re.I|re.M|re.S)

posted @ 2020-12-13 19:50  十九分快乐  阅读(50)  评论(0编辑  收藏  举报