25 -1 正则 re模块 (findall、search、match、sub、subn、split、compile、finditer)

帮助学习的工具 http://tool.chinaz.com/regex/  


字符组 []
在一个字符的位置上能出现的内容
[1bc]         是一个范围
[0-9][A-Z][a-z] 匹配三个字符
[abc0-9] 匹配一个字符
[0-9a-zA-Z] 匹配一个字符

[1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9X]
18位身份证号

 

\d == [0-9]       也表示匹配一个字符,匹配的是一个数字
\w == [0-9a-zA-Z_]  也表示匹配一个数字字母下划线
\s == [\n \t]    包括回车 空格 和 制表符tab
\n           匹配回车
\t           匹配制表符 (tab)
\D           匹配非数字
\W           匹配非数字字母下滑线
\S           匹配非空白
[\d\D] [\w\W] [\s\S]
匹配所有
正则表达式的语法

作用 : 一种匹配字符串的规则
应用 : 登录注册的表单验证
爬虫 自动化开发 日志分析


1. 元字符
字符组 [] [^] | ()
|的用法   [1-9]\d{16}[0-9X]|[1-9]\d{14} 身份证号
()的用法   [1-9]\d{14}(\d{2}[1-9X])?   身份证号
  \d+(\.\d+)?          小数或者整数
\w \d \s(\n,\t, ) \W \D \S
^ $
.       匹配除了换行符之外的所有字符 爬虫容易用,表单不容易用

    
   2. 量词
    ? 0-1
      + 1-无穷
       * 0-无穷
     {n},{n,},{n,m}
    3.特殊的用法和现象
    ?的使用
  1. 在量词的后面跟了一个 ? 取消贪婪匹配 非贪婪(惰性)模式
    ?? \ *? \+? \ {n}?
  李.{1,3}?和 李莲英和 惰性匹配 回溯算法
  最常用 .*?x 匹配任意字符直到找到一个x
总结
元字符
元字符量词 默认贪婪匹配- 回溯算法 (先拿他个最大量,然后往回找匹配的)

元字符量词? 表示惰性匹配 - 惰性匹配 (一个个匹配,有了就停止匹配了)

1、匹配任意长度的正整数   [1-9]\d*
2、匹配小数       -?\d+\.\d+
3、匹配整数或者小数:
  -?\d+\.?\d*    有缺陷 1. 2.这样的内容都能被匹配上
  -?\d+\.?\d+ 有缺陷 1 2 这样的一位数都匹配不上了
  -?\d+(\.\d+)? 准确的
4、匹配负数    -0\.\d+|-[1-9]\d+(\.\d+)?
5、匹配qq号   [1-9]\d{4,11}
6、匹配长度为11位的电话号码 1[3-9]\d{9}
7、长度为8-10位的用户密码 : 包含数字字母下划线和?@
[\w@?]{8,10}
8、匹配验证码:4位数字字母组成的
[\da-zA-Z]{4}

9、从类似
<a>wahaha<\a>
<b>banana<\b>
<h1>qqxing<h1>
<script>salkdjgh<\script>
这样的字符串中,
1)匹配出wahaha,banana,qqxing内容。 >\w+<
2)匹配出a,b,h1这样的内容         <\w+>

10、1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))
从上面算式中匹配出最内层的小括号
(-40/5)(9-2*5/3+7/3*99/4*2998+10*568/14)(-4*3)(16-3*2)
\([\d\.+\-*/]+\)
\([^()]+\)

正则表达式中的转义 :
  
'\('  表示匹配小括号

[()+*?/$.]   在字符组中一些特殊的字符会现出原形

[-]只有写在字符组的首位的时候表示普通的减号,写在其他位置的时候表示范围[1-9],如果就是想匹配减号 [1\-9]

 python中的转义符
  
'\n'  # \转义符 赋予这个n一个特殊的意义 表示一个换行符

print('\\n')     # 取消转义 \n

print('C:\\next')  # 取消转义 C:\next   等同于 print(r'C:\next')
 
re模块 
  对字符串 进行匹配
  一 、findall (重要)
    
ret = re.findall('\d+','19874ashfk01248')

print(ret)      # 参数 返回值类型:列表 返回值个数:1 返回值内容:所有匹配上的项   ['19874', '01248']

 

  二、search (重要)

匹配到

ret2 = re.search('\d+','@$19874ashfk01248')
print(ret2) #  返回值类型: 正则匹配结果的对象  返回值个数:1 如果匹配上了就返回对象
# <re.Match object; span=(2, 7), match='19874'>
if ret2:print(ret2.group()) # 返回的对象通过group来获取匹配到的第一个结果 
# 19874
 

没匹配到

ret3 = re.search('\s+','19874ashfk01248')
print(ret3) #  返回值类型: None   如果没有匹配上就是None

 

三 、match (一般)

  

ret4 = re.match('\d+','19874ashfk01248')
print(ret4)     # <re.Match object; span=(0, 5), match='19874'>
ret5 = re.match('\d+','%^19874ashfk01248')
print(ret5)   # None


print(ret4.group())   # 19874

四、替换 python

  1、自带替换 replace

  

print('replace789,24utdeedeeeeshf'.replace('e','H',3))    # e替换成H ,替换3个
 # rHplacH789,24utdHedeeeeshf

 

  2、re 的sub  (一般)

ret = re.sub('\d+','H','replace789nbc2xcz392zx')   # 正则,替换内容,字符串
print(ret)       # replaceHnbcHxczHzx
ret = re.sub('\d+','H','replace789nbc2xcz392zx,48495',1)
print(ret)     #  replaceHnbc2xcz392zx,48495

  3、subn(一般)

ret = re.subn('\d+','H','replace789nbc2xcz392zx')  #正则,替换值,字符串
print(ret)    # 返回一个元组 (替换后的字符串,替换次数)
# ('replaceHnbcHxczHzx', 3)

 

五、切割

split
1、python 内置函数
print('alex|83|'.split('|'))      # ['alex', '83', '']

  2、re中的split

ret = re.split('\d+','alex83egon20taibai40') 
print(ret)    #['alex', 'egon', 'taibai', '']

 

六、进阶方法 - 爬虫\自动化开发

1、compile  (重要)-----节省时间

 一般都是直接带入正则表达式,直接匹配结果,当要重复使用改正则表达式,程序就要重新编译理解它,继而导致程序效率低
re.findall('-0\.\d+|-[1-9]+(\.\d+)?','alex83egon20taibai40')  #  --> python解释器能理解的代码 --> 执行代码

 

那,如何让程序更加高效呢? 我们可以使用预编译compile ,程序直接调用编译结果使用即可,不用重复编译了

    (节省时间 : 只有在多次使用某一个相同的正则表达式的时候,这个compile才会帮助我们提高程序的效率)

ret = re.compile('-0\.\d+|-[1-9]\d+(\.\d+)?')
res = ret.search('alex83egon-20taibai-40')


res2 = ret.search('...')
res3 = ret.search('...')
...
print(res.group())

2、finditer (重要)--节省空间
  
print(re.findall('\d','sjkhkdy982ufejwsh02yu93jfpwcmc'))
ret = re.finditer('\d','sjkhkdy982ufejwsh02yu93jfpwcmc')     # 得到了一个迭代器(可迭代对象)
for r in ret:
    print(r.group())


--------------------------------
9
8
2
0
2
9
3

关于分组的坑


findall 关于分组的坑--- 分组的优先显示
                优先显示分组内的内容
import re
ret = re.findall('-0\.\d+|-[1-9]\d*(\.\d+)?','-1asdada-200')
print(ret)     # ['', '']
ret = re.findall('www.baidu.com|www.oldboy.com','www.oldboy.com')
print(ret)      # ['www.oldboy.com']


ret = re.findall('www.(baidu|oldboy).com','www.oldboy.com')
print(ret)      #   ['oldboy']
ret = re.findall('www.(?:baidu|oldboy).com','www.oldboy.com')
print(ret)      # 取消分组优先(?:) ['www.oldboy.com']

 

split 遇到分组 会保存被切掉的内容

ret = re.split('\d+','alex83egon20taibai40')
print(ret)
ret
= re.split('(\d+)','alex83egon20taibai40') print(ret) # 遇到分组,保存被切掉的内容 ---------------------------------------------------- ['alex', 'egon', 'taibai', ''] ['alex', '83', 'egon', '20', 'taibai', '40', '']

search遇到分组
    通过group(n)就能拿到group中的匹配的内容
ret = re.search('\d+(.\d+)(.\d+)(.\d+)?','1.2.3.4-2*(60+(-40.35/5)-(-4*3))')
print(ret.group())
print(ret.group(1))
print(ret.group(2))
print(ret.group(3))

---------------------------
1.2.3.4
.2
.3
.4

 

小试牛刀

 

一、要求匹配到表达式"1-2*(60+(-40.35/5)-(-4*3))"中所有整数

1.拿到所有的数,(然后把小数去掉)

import re

ret = re.findall(r"\d+(?:\.\d+)?", "1-2*(60+(-40.35/5)-(-4*3))")
print(ret)
View Code

2.直接匹配所有整数

分组思路,我不想要小数,但是无法避免,我就匹配小数,但是咱不显示你就行了

# 思路是 我们匹配小数|整数,但是小数取消优先显示,优先显示的是后面的整数,即得到结果
ret = re.findall(r"\d+(?:\.\d+)|(\d+)", "1-2*(60+(-40.35/5)-(-4*3))")
print(ret)   # ['1', '2', '60', '', '5', '4', '3']
ret.remove('')  # ['1', '2', '60', '5', '4', '3']
print(ret)

 

二、匹配html 标签内容

1、匹配<a>wahaha<\a>

  

import re
ret = re.findall('>(\w+)<',r'<a>wahaha<\a>')
print(ret)    # ['wahaha']

2、嘿,那假如想匹配两端标签不同的中间内容呢<a>wahaha</b>  (当然这是假设)

# 利用分组!
ret = re.search(r'<(\w+)>(\w+)</(\w+)>', r'<a>wahaha</b>')
print(ret.group())
print(ret.group(1))
print(ret.group(2))



--------------------------------
<a>wahaha</b>
a
wahaha

 

七、分组命名  

        (?P<name>正则表达式)

1、通过group(分组名),获取值
ret = re.search("<(?P<name>\w+)>\w+</(?P=name)>","<h1>hello</h1>")
print(ret.group('name'))    # 结果 :h1
print(ret.group())          # 结果 :<h1>hello</h1>

 同样的通过group(n),当然也是可以的呀

ret = re.search(r"<(\w+)>\w+</\1>","<h1>hello</h1>")
print(ret.group(1))
# print(ret.group())  #结果 :<h1>hello</h1>

同样的 :

ret = re.search(r'<(?P<tag>\w+)>(?P<c>\w+)</(\w+)>', r'<a>wahaha</b>')
print(ret.group())          # <a>wahaha</b>
print(ret.group('tag'))     # a
print(ret.group('c'))       # wahaha

推荐一本正则的书 :《正则指引》        -------- 以python 为基础的书


小拓展

1.groups()是什么?
import re
ret = re.search(r'\d+(\.\d)(\d)',r'1.23+2.3+3-4*5')
print(ret.group())
print(ret.group(1))
print(ret.group(2))
print(ret.groups())

——————————————————————
1.23
.2
3
('.2', '3')     # 可知,groups() 获取分组内的内容,以str形式放入元组内
View Code

 

2.split 分组保留
import re
ret3 = re.split('\d(\w)', '***1a***2b***3c**')
print(ret3)     #  ['***', 'a', '***', 'b', '***', 'c', '**']

# 以数字+数字字母下划线  的组合切开,但是保留后面的分组了

 





posted @ 2020-04-06 20:27  蜗牛般庄  阅读(436)  评论(0编辑  收藏  举报
Title
页脚 HTML 代码