precipitation

1.正则概述

就其本质而言,正则表达式(或 RE)是一种小型的、高度专业化的编程语言,要讲他的具体用法要讲一本书!它内嵌在Python中,并通过 re 模块实现。你可以为想要匹配的相应字符串集指定规则;该字符串集可能包含英文语句、e-mail地址、TeX命令或任何你想搞定的东西。然后你可以问诸如“这个字符串匹配该模式吗?”或“在这个字符串中是否有部分匹配该模式呢?”。你也可以使用 RE 以各种方式来修改或分割字符串。今天就来讲讲re模块的最常用的用法

http://tool.chinaz.com/regex

2.常用元字符

字符组:在同一个位置可能出现的各种字符组成了一个字符组,在正则表达式中用[]表示字符分为很多类,比如数字、字母、标点等等。假如你现在要求一个位置"只能出现一个数字",那么这个位置上的字符只能是0、1、2...9这10个数之一。

正则 待匹配元字符 匹配结果 说明
[0123456789] 8 True 在一个字符组里枚举合法的所有字符,字符组里的任意一个字符和"待匹配字符"相同都视为可以匹配
[0123456789] a False 由于字符组中没有"a"字符,所以不能匹配
[0-9] 7 True 也可以用-表示范围,[0-9]就和[0123456789]是一个意思
[a-z] s True 同样的如果要匹配所有的小写字母,直接用[a-z]就可以表示
[A-Z] B True [A-Z]就表示所有的大写字母
[0-9a-fA-F] e True 可以匹配数字,大小写形式的a~f,用来验证十六进制字符
元字符 匹配内容
. 匹配换行符以外的任意字符
\w 匹配字母或数字或下划线
\s 匹配任意的空白字符
\d 匹配数字
\n 匹配一个换行符
\t 匹配一个制表符
\b 匹配一个单词的结尾
^ 匹配字符换的开头
$ 匹配字符串的结尾
\W 匹配非字母或数字或下划线
\D 匹配非数字
\S 匹配非空白符
a|b 匹配字符a或者b
[^....] 匹配除了字符组中字符的所有字符
() 匹配括号内的表达式也表示一个组(www\.(baidu|jd|taobao)\.com)

3.量词

  • {n}
    表示匹配n次
    \d{2} 只能匹配两位整数

  • {n,}
    表示匹配至少n次
    [1-9]{3,} 至少匹配三位的数字

  • {n,m}
    表示至少匹配nci至多m次
    [1-9]{1,3}\.[1-9]{1,3}\.[1-9]{1,3}\.[1-9]{1,3}

  • *
    重复零次或更多次

  • +
    重复一次或多次

  • ?
    重复零次或一次

3.1 练习

`\d+\.\d|\d+`   匹配整数或者是小数
`\d+\.?\d*`       匹配整数或者是小数 (?表示匹配0个点或者是匹配一个点)
\d+(\.\d+)?      正规的
  • 匹配手机号码 11位数 以1开头 第二个数是3-9
    ^[1][3-9]+\d{9}$

  • 判断用户输入的内容是否合法,如果用户输入的对就能查到结果,如果输入的不对就不能查到结果   
    ^1[3-9]\d{9}$

  • 从一个大文件中找到所有符合规则的内容   
    1[3-9]\d{9}

  • 匹配身份证号
    18/15位的身份证号

    • 15
      • 1-9 15
        • [1-9]\d{14}
    • 18
      • 1-9 16 0-9/x
        • [1-9]\d{16}[\dx]
          • [1-9]\d{16}[0-9x]

4.正则的贪婪匹配和惰性匹配

  • 在量词范围允许的情况下,尽量多的匹配内容
    .*x  表示匹配任意字符 任意多次数 遇到最后一个x才停下
    \d{3,}6

  • 非贪婪
    # .*?x  表示匹配任意字符 任意多次数 但是一旦遇到x就停下来

    \d{3,}?6

5.转义符

原本有特殊意义的字符,到了表达它本身的意义的时候,需要转义

有一些特殊意义的内容,放在字符组中,会取消它的特殊意义

  • [().*+?]

[a\-c]  - 在字符组中表示范围,如果不希望它表示范围,需要转义,或者放在字符组的最前面\最后面

取消一个元字符的特殊意义的两种方法

  • 在这个元字符前面加上\
  • 对一部分元字符生效,把这个元字符放在字符组里

匹配1+2 或者是 1-2
1[+-]2

6.re模块方法

6.1.1 findall返回所有满足匹配条件的结果

结果返回的是一个列表

import re
ret = re.findall(\'\d\',\'123123sdasd\')
print(ret)
>>>
[\'1\', \'2\', \'3\', \'1\', \'2\', \'3\']

import re
ret = re.findall(\'[a-z]\',\'123123sdasd\')
ret2 = re.findall(\'[sd]\',\'123123sdasd\')
print(ret)
print(ret2)
>>>
[\'s\', \'d\', \'a\', \'s\', \'d\']
[\'s\', \'d\', \'s\', \'d\']
  • 函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以
  • 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。
ret = re.search(\'[a-z]\',\'12312dsfsdf3243\')
print(ret.group())
>>>
d           #只返回匹配的第一个结果,用group的方法

6.1.3 findall serch与()分组的关系

  • findall
    还是安装完整的正则进行匹配,只是显示括号内匹配到的内容
import re
ret = re.findall(\'2(\d)\d\',\'123123sdasd\')
print(ret)
>>>
[\'3\']
  • search
    • 还是安装完整的正则进行匹配,显示匹配到第一个内容,但是我们可以通过给group方法进行传参数,来获取具体文组中的内容
    • 得到的是一个变量
    • 变量.group()的结果 完全和变量.group(0)的结果一致
    • 变量.group(n)的形式指定获取第n个分组中匹配到的内容
ret = re.search(\'2(\d)\d\',\'12312dsfsdf3243\')
print(ret.group())
>>>
231
ret = re.search(\'2(\d)(\d)\',\'12312dsfsdf3243\') 
print(ret.group(2))
>>>
1
ret = re.search(\'^<h1>(.*)</h1>$\',\'<h1>asdsadasd23232</h1>\')
print(ret.group(1))
>>>
asdsadasd23232

范例:
加上括号是为了对真正需要的内容进行提取

ret = re.search(\'^<h1>(.*)</h1>$\',\'<h1>asdsadasd23232</h1>\')
print(ret.group(1))

ret = re.findall(\'^<h1>(.*)</h1>$\',\'<h1>asdsadasd23232</h1>\')
print(ret)
>>>
asdsadasd23232
[\'asdsadasd23232\']
  • 匹配exp 中的 5+6 并让相加得出结果
exp = \'2-3*(5+6)\'
ret = re.search(\'[(](\d)[+](\d)\)$\',exp)
print(ret.group(1))
print(ret.group(2))
print(int(ret.group(1))+int(ret.group(2)))

ret = re.search(\'(\d)[+](\d)\',exp)
print(ret.group(1))
print(ret.group(2))
print(int(ret.group(1))+int(ret.group(2)))

6.1.4 匹配电影名

import re
with open(\'douban.html\',mode=\'r\',encoding=\'utf-8\')as f:
    info = f.read()
ret = re.findall(\'<span class="title">(.*?)</span>\s*<span class="title">.*</span>\',info)
#<span class="title">机器人总动员</span>                          
             #<span class="title">&nbsp;/&nbsp;WALL·E</span>
print(ret)
>>>
[\'肖申克的救赎\', \'这个杀手不太冷\', \'阿甘正传\', \'美丽人生\', \'泰坦尼克号\', \'千与千寻\', \'辛德勒的名单\', \'盗梦空间\', \'忠犬八公的故事\', \'机器人总动员\', \'三傻大闹宝莱坞\', \'海上钢琴师\', \'放牛班的春天\', \'楚门的世界\', \'大话西游之大圣娶亲\', \'星际穿越\', \'龙猫\', \'教父\', \'熔炉\', \'无间道\', \'疯狂动物城\', \'当幸福来敲门\', \'怦然心动\', \'触不可及\']

6.1.5 取链家相关信息

使用findall
范例:

ret = re.findall(\'<div class="title">.*?data-sl="">(.*?)</a>.*?<span class="divide">/</span>(.*?)<span class.*?</span>(.*?)<span class="divide">\',info,flags=re.S)
print(ret)
>>>
[(\'金台路交通部部委楼南北大三居带客厅   单位自持物业\', \'3室1厅\', \'91.22平米\'), (\'西山枫林 高楼层南向两居 户型方正 采光好\', \'2室1厅\', \'94.14平米\')]

正则解释
(\'

.?data-sl="">(.?).?/(.?)<span class.?(.?)\',info,flags=re.S)

  • 匹配全文
    .*?data-sl="">(遇到data-sl="">就结束)
  • 匹配全文(.*?)遇到就结束这时匹配的是\'金台路交通部部委楼南北大三居带客厅 单位自持物业\'
  • 匹配全文.*?/遇到/就结束
    以此类推

6.1.6 匹配网站标签

import re
exp = \'<h1>asddasdsd</h1></asdsd>\'
ret = re.search(\'<\w+>.*?</\w+>\',exp)
print(ret.group())
>>>
<h1>asddasdsd</h1>

6.2 finditer

finditer方法finditer函数跟findall函数类似,但返回的是一个迭代器, 而不是一个像findall函数那样的存有所有结果的list。finditer的每一个对象可以使用group(可以获取整个匹配串)和groups方法;在有分组的情况下,findall只能获得分组,不能获得整个匹配串。

6.2.1 取链家的相关信息

范例:

import re
ret = re.finditer(\'<div class="title">.*?data-sl="">(?P<name>.*?)</a>.*?<span class="divide">/</span>(?P<room>.*?)<span class.*?</span>(?P<area>.*?)<span class="divide">\',info,flags=re.S)

for i in ret:   #遍历取出
    print(i.group(\'name\'),i.group(\'room\'),i.group(\'area\'))
>>>
金台路交通部部委楼南北大三居带客厅   单位自持物业 3室1厅 91.22平米
西山枫林 高楼层南向两居 户型方正 采光好 2室1厅 94.14平米

7.re模块中的用法

7.1 split

根据匹配到的内容进行切割

  • 匹配到了222进行以222进行切割(形成列表)
import re
ret = re.split(\'\d+\',\'tom222deam\')  
print(ret)
>>>
[\'tom\', \'deam\']
  • 可以使用分组进行保留(形成列表)
import re
ret = re.split(\'\d(\d)\d\',\'tom222deam\')
print(ret)
>>>
[\'tom\', \'2\', \'deam\']

7.2 sub

替换的方法

  • 我要把字符串中的数字替换成“SED”
import re
ret = re.sub(\'\d+\',\'SED\',\'tom12323deam123123\') 
print(ret)
>>>
tomSEDSEDSEDSEDSEDdeamSEDSEDSEDSEDSEDSED

ret = re.sub(\'\d+\',\'SED\',\'tom12323deam123123\')
print(ret)
>>>
tomSEDdeamSED
  • 也可以传入参数
ret=re.sub(\'\d\',\'SED\',\'tom12323deam123123\',1) #后面加上一表示只替换一个从左往右的顺序
print(ret)

>>>
tomSED2323deam123123

7.3 match

  • 表示以你的匹配条件开头进行匹配
ret=re.match(\'\d+\',\'132434aasd123213fdf\')
print(ret.group())  #相当于^
>>>
132434

7.4 compile

节省了代码的时间

  • 使用compile进行定义的正则可以多次调用
import re
ret = re.compile(\'\d+\')
ret = ret.findall(\'123sdsdsd323\')
print(ret)
>>>
[\'123\', \'323\']

7.5 finditer

  • 节省空间
  • 形成了迭代器 返回的是结果变量 使用i.group()进行取值
ret = re.compile(\'\d+\')
ret = ret.finditer(\'123sdsdsd323\')

for i in ret:
    print(i)
    
>>>
<re.Match object; span=(0, 3), match=\'123\'>
<re.Match object; span=(9, 12), match=\'323\'>
ret = re.compile(\'\d+\')
ret = ret.finditer(\'123sdsdsd323\')

for i in ret:
    print(i.group()
>>>
123
323

7.6 分组命名

(?P<名字>正则表达式)

范例:

import re
ret = re.finditer(\'<div class="title">.*?data-sl="">(?P<name>.*?)</a>.*?<span class="divide">/</span>(?P<room>.*?)<span class.*?</span>(?P<area>.*?)<span class="divide">\',info,flags=re.S)

for i in ret:   #遍历取出
    print(i.group(\'name\'),i.group(\'room\'),i.group(\'area\'))
>>>
金台路交通部部委楼南北大三居带客厅   单位自持物业 3室1厅 91.22平米
西山枫林 高楼层南向两居 户型方正 采光好 2室1厅 94.14平米

7.6.1 分组命名的引用

  • 匹配标签 约束

    ==


    引用了分组名 约束了

    必须是

exp = \'<h1>asddasdsd</h1></asdsd>\'

ret = re.search(\'<(?P<tag>\w+)>.*?</(?P=tag)>\',exp)
print(ret.group())
>>>
<h1>asddasdsd</h1>

分类:

技术点:

相关文章: