035.Python正则表达式


正则表达式 

一 介绍

拼正则表达式是什么?

  • 它是约束字符串匹配某种形式的规则

正则表达式有什么用?

  1. 检测某个字符串是否符合规则比如:判断手机号,身份证号是否合法
  2. 提取网页字符串中想要的数据.比如:爬虫中,提取网站天气,信息,股票代码,星座运势等具体关键字

线测试工具http://tool.chinaz.com/regex

正则表达式由一些[普通字符]和一些[元字符]组成:

(1)普通字符包括大小写字母和数字

(2)元字符具有特殊含义,大体种类分为如下

  1. 预定义字符集,字符组
  2. 量词
  3. 边界符
  4. 分组

二 正则表达式findall

2.1 单字符匹配

findall("正则表达式","要匹配的字符串")

d 和 D

  • d 匹配数字
  • D 匹配非数字
import re
lst = re.findall("d","davfdardwer24523`de3r43wqe#$@!dwd@#!2143DC")
print (lst)
lst = re.findall("D","davfdardwer24523`de3r43wqe#$@!dwd@#!2143DC")
print (lst)

执行

[root@node10 python]# python3 test.py
['2', '4', '5', '2', '3', '3', '4', '3', '2', '1', '4', '3']
['d', 'a', 'v', 'f', 'd', 'a', 'r', 'd', 'w', 'e', 'r', '`', 'd', 'e', 'r', 'w', 'q', 'e', '#', '$', '@', '!', 'd', 'w', 'd', '@', '#', '!', 'D', 'C']

w和W

  • w 匹配字母数字下换线 (正则函数中,支持中文匹配)
  • W 匹配非字母,数字,下划线
import re
lst = re.findall("w","dwer_=|:';.你好世界24523`de3re#$@!dwd@#!2143DC")
print (lst)
lst = re.findall("W","dwer_=|:';.你好世界24523`de3re#$@!dwd@#!2143DC")
print (lst)

执行

'd', 'w', 'e', 'r', '_', '你', '好', '世', '界', '2', '4', '5', '2', '3', 'd', 'e', '3', 'r', 'e', 'd', 'w', 'd', '2', '1', '4', '3', 'D', 'C']
['=', '\', '|', ':', "'", ';', '.', '`', '#', '$', '@', '!', '@', '#', '!']

s和S

  • s 匹配任意的空白符( )
  • S 匹配任意的非空白符
复制代码
import re
strvar = '                                      '
lst = re.findall("s",strvar)
print(lst)
strvar = "  8989sdf     111"
lst = re.findall("S",strvar)
print(lst)
复制代码

执行

[root@node10 python]# python3 test.py
[' ', '	', '	', '	', '	', '	']
['8', '9', '8', '9', 's', 'd', 'f', '1', '1', '1']

  • 匹配一个换行
  • 匹配一个缩进
复制代码
import re
strvar = """
sdfsd   sdfsdf   sfsdfsdf
sdfsddffg       dfgdfg  fgdfg
"""
lst = re.findall("
",strvar)
print(lst)
lst = re.findall("	",strvar)
print(lst)
复制代码

字符组 [123]

[123] 必须从字符组当中挑出一个出来,个数上有要求,必须一个,如果匹配不到就是空.

import re
lst = re.findall("[123]","sdfs3fkj5kj")
print(lst)

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

执行

[root@node10 python]# python3 test.py
['3']
['aab', 'abb', 'acb']

字符组

复制代码
import re
# [0123456789] => [0-9] -是一个特殊字符,代表范围0-9 0到9
print(re.findall('a[0123456789]b','a1b a2b a3b acb ayb'))
print(re.findall("a[0-9]b",'a1b a2b a3b acb ayb'))

#[abcdefg] => [a-g] 表达所有小写字符可以用[a-z]
print(re.findall('a[a-z]b','a1b a2b a3b acb ayb adb')) #['acb', 'ayb', 'adb']
# print(re.findall('a[abcdefg]b','a1b a2b a3b acb ayb adb')) #['acb', 'adb']

# [ABCDEFG] A-G  [A-Z]用来表达所有大写字符
print(re.findall('a[A-Z]b','a1b a2b a3b  aAb aDb aYb')) #['aAb', 'aDb', 'aYb']
print(re.findall('a[ABCDEFG]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']
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']
# 在特殊字符前面加商一个\,让原本有意义的字符变得无意义,用于正则字符匹配
print(re.findall('a[^]b',"a^b")) #['a%b', 'a&b']
复制代码

执行

复制代码
[root@node10 python]# python3 test.py
['a1b', 'a2b', 'a3b']
['a1b', 'a2b', 'a3b']
['acb', 'ayb', 'adb']
['aAb', 'aDb', 'aYb']
['aAb', 'aDb']
['aab', 'aAb', 'aWb', 'aqb', 'a1b']
['a1/b']
['a%b', 'a&b']
['a^b']
复制代码

2.2 正则匹配多个字符

量词

复制代码
import re
'''1) ? 匹配0个或者1个a '''
print(re.findall('a?b','abbzab abb aab'))
'''2) + 匹配1个或者多个a '''
print(re.findall('a+b','b ab aaaaaab abb'))
'''3) * 匹配0个或者多个a '''
print(re.findall('a*b','b ab aaaaaab abbbbbbb'))
'''4) {m,n} 匹配m个至n个a '''
print(re.findall('a{1,3}b','aaab ab aab abbb aaz aabb'))
复制代码

执行

[root@node10 python]# python3 test.py
['ab', 'b', 'ab', 'ab', 'b', 'ab']
['ab', 'aaaaaab', 'ab']
['b', 'ab', 'aaaaaab', 'ab', 'b', 'b', 'b', 'b', 'b', 'b']
['aaab', 'ab', 'aab', 'ab', 'aab']

2.3 贪婪匹配 和 非贪婪匹配

贪婪匹配:

  • 默认向更高次数匹配,程序当中默认使用贪婪匹配

非贪婪匹配:

  • 默认向更少次数匹配
  • 语法:只需要在量词的后面再加上一个?号

底层用的时回溯算法:
从左到右开始寻找,直到找到最后再也找不到了,回头,找离右侧最近的那个值返回

复制代码
import re
strvar = "刘能和刘罗锅和刘备有3儿子4"
#.表示除了
以外的任意字符
lst = re.findall("刘.",strvar) print (lst) #.?表示刘后的字符可以出现1次或者多个
lst = re.findall("刘.?",strvar) print(lst) #.+表示刘后的的任意字符出现0个或者多个
lst = re.findall("刘.+",strvar) print(lst)
lst = re.findall("刘.*",strvar) print(lst)
lst = re.findall("刘.*子",strvar) print(lst)
lst = re.findall("刘.{1,20}",strvar) print(lst) lst = re.findall("刘.{1,20}子",strvar) print(lst) print("非贪婪匹配") lst = re.findall("刘.??",strvar) print(lst) lst = re.findall("刘.+?",strvar) print(lst) lst = re.findall("刘.*?",strvar) print(lst) lst = re.findall("刘.*?子",strvar) print(lst) lst = re.findall("刘.{1,20}?",strvar) print(lst) # 默认使用的是贪婪模式,一直找到最后一个子,如果使用非贪婪,找到第一个字就立刻返回. lst = re.findall("刘.{1,20}?子",strvar) print(lst)
复制代码

执行

复制代码
['刘能', '刘罗', '刘备']
['刘能', '刘罗', '刘备']
['刘能和刘罗锅和刘备有3儿子4子']
['刘能和刘罗锅和刘备有3儿子4子']
['刘能和刘罗锅和刘备有3儿子4子']
['刘能和刘罗锅和刘备有3儿子4子']
['刘能和刘罗锅和刘备有3儿子4子']
非贪婪匹配 ['刘', '刘', '刘'] ['刘能', '刘罗', '刘备'] ['刘', '刘', '刘'] ['刘能和刘罗锅和刘备有3儿子'] ['刘能', '刘罗', '刘备'] ['刘能和刘罗锅和刘备有3儿子']
复制代码

2.4 边界符 ^ $

例: w 以w作为左边界  d 以d作为右边界

 它默认是一个转义字符 退格 backspace
需要通过字符串前面加上r,让转义字符失效,呈现正则的含义.

复制代码
import re
#只匹配右边界d lst = re.findall(r"d","word pwd abc") print(lst)
#匹配右边界前的任意字符 lst = re.findall(r".*d","word pwd abc") print(lst) # 能够匹配到一个右边界d ,就立刻返回 # .可以匹配空白符,除了 ,剩下所有字符都能匹配到 lst = re.findall(r".*?d","word pwd abc") print(lst)
#匹配到非空白符 lst = re.findall(r"S*?d","word pwd abc") # 纯单词,舍去空格 print(lst)
#匹配以w开头的非空白符 lst = re.findall(r"wS*","word pwd abc") #'word' print(lst)
复制代码

执行

复制代码
[root@node10 python]# python3 test.py
['d', 'd']
['word pwd']
['word', ' pwd']
['word', 'pwd']
['word']
复制代码

2.5 使用^$

  • 如果使用了^ 或者 $
  • ^ : 必须以某个字符开头,后面剩下的无所谓
  • $ : 必须以某个字符结尾,前面剩下的无所谓
  • 意味着把这个字符串当成一个整体
复制代码
import re
strvar = "大哥大嫂大爷"
print ("匹配大后面出\n的任意字符")
print(re.findall('大.',strvar))
print ("匹配以大开头后面出
的任意字符,同时把这个字符串看成一个整体")
print(re.findall('^大.',strvar)) # 只匹配一个,把字符串开成整体
print ("必须以一个任意字符结尾")
print(re.findall('大.$',strvar)) # 只匹配一个,把字符串开成整体
# strvar = "大书"
print ("以大开头,以任意字符结尾的两个字符,为空")
print(re.findall('^大.$',strvar))
print ("以大开头,匹配.*,?只是非贪婪匹配")
print(re.findall('^大.*?$',strvar))
print ("以g开头,匹配到空格停止")
print(re.findall('^g.*? ' , 'giveme 1gfive gay'))
print ("以e结尾,向前找到five,打出 ")
print(re.findall('five$' , 'aassfive'))
print ("以c结尾,匹配abc打印")
print(re.findall("abc$","abcabcabc"))
print ("全部卡死")
print(re.findall('^giveme$' , 'giveme'))
print ("完全卡死,并不匹配,返回空")
print(re.findall('^giveme$' , 'giveme giveme'))
print ("以g开头,e结尾,中间匹配任意")
print(re.findall('^g.*?e$' , 'giveme giveme'))
print ("匹配giveme,有两个")
print(re.findall('giveme' , 'giveme giveme'))
print ("以g开头,卡到e")
print(re.findall("^g.*e",'giveme 1gfive gay'))
print ("以g开头,卡到e,并使用非贪婪匹配")
print(re.findall("^g.*?e",'giveme 1gfive gay'))
复制代码

执行

复制代码
[root@node10 python]# python3 test.py
匹配大后面出
的任意字符
['大哥', '大嫂', '大爷']
匹配以大开头后面出
的任意字符,同时把这个字符串看成一个整体
['大哥']
必须以一个任意字符结尾
['大爷']
以大开头,以任意字符结尾的两个字符,为空
[]
以大开头,匹配.*,?只是非贪婪匹配
['大哥大嫂大爷']
以g开头,匹配到空格停止
['giveme ']
以e结尾,向前找到five,打出
['five']
以c结尾,匹配abc打印
['abc']
全部卡死
['giveme']
完全卡死,并不匹配,返回空
[]
以g开头,e结尾,中间匹配任意
['giveme giveme']
匹配giveme,有两个
['giveme', 'giveme']
以g开头,卡到e
['giveme 1gfive']
以g开头,卡到e,并使用非贪婪匹配
['give']
复制代码

2.6 正则表达式分组匹配

正常分组

  1. 正常情况下用()圆括号进行分组 可以用1 反向引用第一个圆括号匹配的内容。
  2. (?:正则表达式) 表示取消优先显示的功能
复制代码
import re
print("匹配所有_good前的任意字符打印出")
print(re.findall('.*?_good','wusir_good alex_good xboyww_good'))
print("匹配所有的姓名")
print(re.findall('(.*?)_good','wusir_good alex_good xboyww_good'))
print("匹配所有的姓名,然后取消分组")
print(re.findall('(?:.*?)_good','wusir_good alex_good secret男_good'))
复制代码

执行

复制代码
[root@node10 python]# python3 test.py
匹配所有_good前的任意字符打印出
['wusir_good', ' alex_good', ' xboyww_good']
匹配所有的姓名
['wusir', ' alex', ' xboyww']
匹配所有的姓名,然后取消分组
['wusir_good', ' alex_good', ' secret男_good']
复制代码

a|b 匹配字符a 或者 匹配字符b  把字符串长的写在前面,字符串短的写在后面

  • | 代表或的意思
import re
res = re.findall("abcd|abc","abcdabcdabcd abc")
print(res)

执行

[root@node10 python]# python3 test.py
['abcd', 'abcd', 'abcd', 'abc']

2.7 匹配小数

import re
strvar = " 3.14 .34 35. ... 2.41.3 34.."
res  = re.findall("d+.d+",strvar)
print(res)

执行 

[root@node10 python]# python3 test.py
['3.14', '2.41']

匹配小数和整数

import re

strvar = "3.15 34 .. 3434.23.234.2323 .34.34 .3434 .. .. nihao"
res = re.findall("d+.d+|d+",strvar)
print(res)

执行

[root@node10 python]# python3 test.py
['3.15', '34', '3434.23', '234.2323', '34.34', '3434']

优化版

findall 这个函数默认优先显示小括号里面的内容,如果不想显示,用?:
小括号代表的是分组,放到一起代表整体,这个例子要么出现小数点和后面的值,要么不出现.

import re

strvar = "3.15 34 .. 3434.23.234.2323 .34.34 .3434 .. .. nihao"
res = re.findall("d+(?:.d+)?",strvar)
print(res)

执行

[root@node10 python]# python3 test.py
['3.15', '34', '3434.23', '234.2323', '34.34', '3434']

匹配135或171的手机号 

import re
res = re.findall("(?:135|171)d{8}","13588889897 17180668088")
print(res)

执行

[root@node10 python]# python3 test.py
['13588889897', '17180668088']

正则要求卡主开头和结尾,且长度是11位 (这个例子开头结尾满足,但长度不对)

import re
res = re.findall("(?:^135|^171)d{8}$","13588889897 17180668088")
print(res)

执行

[root@node10 python]# python3 test.py
[]

#(?:     ^135      |      ^171     )

import re
res = re.findall("(?:^135|^171)d{8}$","17188889897")
print(res)

执行

[root@node10 python]# python3 test.py
['17188889897']

三 search 正则方法 

3.1 介绍

search("正则表达式","要匹配的字符串")
它返回的是一个对象

  • 对象.属性
  • 对象.方法()
  • 想要获取对象里面的值用group()方法
  • 想要获取分组里面的值用groups()方法

和 findall区别

  1. findall 找出所有匹配的结果,从左到右,返回的是列表
  2. search 找出一个结果就返回,从左到右,返回的是对象
import re
obj = re.search("d+","ksj323rf33sdf*&*&  78787878")
print(obj)
res = obj.group()
print(res)

执行

[root@node10 python]# python3 test.py
<_sre.SRE_Match object; span=(3, 6), match='323'>
323

3.2 基本使用

匹配www.baidu.com 或者 www.google.com

复制代码
import re
obj = re.search("(www).(baidu|google).(com)","www.baidu.com www.google.com")
res = obj.group()
#通过group拿到实际匹配的内容 print(res) #通过groups拿到小括号里面匹配的内容
res = obj.groups() print(res)
复制代码

执行

[root@node10 python]# python3 test.py
www.baidu.com
('www', 'baidu', 'com')

同一时间,既可以拿到匹配的结果,又可以拿到小括号里的内容,而findall不具备

findall 同一时间只能拿取一种结果,要么是实际匹配的,要么是小括号的.

search 只能匹配一个, findall 可以匹配所有. 这是两个函数之间的差别.

复制代码
import re
obj = re.search("(www).(baidu|google).(com)","www.baidu.com www.google.com")
res = obj.group()
print(res) #www.baidu.com
res = obj.groups()
print(res)
res = re.findall("(www).(baidu|google).(com)","www.baidu.com www.google.com")
print(res)
复制代码

执行

[root@node10 python]# python3 test.py
www.baidu.com
('www', 'baidu', 'com')
[('www', 'baidu', 'com'), ('www', 'google', 'com')]

3.3 对比两个函数区别

匹配出5*4 或者 6/8

复制代码
import re
strvar = "5*4+6/8"
obj = re.search("d+[*/]d+",strvar)
# 获取对象当中的值
res = obj.group()
print(res)

res= re.findall("d+[*/]d+",strvar)
print(res)
复制代码

执行

[root@node10 python]# python3 test.py
5*4
['5*4', '6/8']

一般有分组的情况下用search 更多,找到所有匹配条件一般用findall

学习记录,小白一枚
原文地址:https://www.cnblogs.com/wangsirde0428/p/14322631.html