文章目录
介绍
python re 模块-正则- python 官方文档 中文
书籍推荐
Jeffrey E. F. Friedl的《Mastering Regular Expressions》
一书,
Michael Fitzgerald的《Introducing Regular Expressions》
,
Jan Goyvaerts和Steven Levithan写的《Regular Expressions Cookbook》
都是
O'Reilly
出版社出版,这些书都非常受欢迎。
regex101
对于新手是特别有用的网站,可以自动生成正则表达式的解读。
正则表达式
用于搜索
、 替换
和解析
字符串
。 正则表达式遵循一定的语法规则
, 使用非常灵活, 功能强大。 使用正则表达式编写一些逻辑验证非常方便
, 例如电子邮件地址格式的验证
。
正则表达式
是对字符串
(包括普通字符(例如, a 到 z 之间的字母) 和特殊字符) 操作
的一种逻辑公式
, 就是用事先定义好的一些特定字符
、 及这些特定字符的组合
, 组成一个“规 则字符串”
, 这个“规则字符串”
用来表达对字符串的一种过滤逻辑
, 正则表达式是一种文 本模式
, 模式描述在搜索文本时要匹配一个或多个字符串。
一开始的例子 如果看不懂 可以先 跳过。
然后看 search
和 match
方法 。 接着 回过头来 看 常用匹配字符串
然后顺序往下看。
当然也可以根据自己的想法 ,随意观看。
例子
In [16]: import re
In [17]: pat=r'P(Y|YT|YTH|YTHO)?N'
In [18]: p=re.compile(pat) # 面向对象 编译 。 多次使用的正则
In [19]: p.findall("i love PN PYN PYTN PYTHN PYTHON PDADN")
Out[19]: ['', 'Y', 'YT', 'YTH', 'YTHO']
In [21]: p.search("i love PN PYN PYTN PYTHN PYTHON PDADN")
Out[21]: <_sre.SRE_Match object; span=(7, 9), match='PN'>
# 当然你也可以使用这种方式 单次 使用。
In [22]: re.findall(pat,"i love PN PYN PYTN PYTHN PYTHON PDADN")
Out[22]: ['', 'Y', 'YT', 'YTH', 'YTHO']
# ---------------------------
In [23]: pat=r'PYTHON+'
In [24]: p=re.compile(pat)
In [25]: p.findall("PYTHONN PYTHONNNN PYTHONN PYTHON PYTHO")
Out[25]: ['PYTHONN', 'PYTHONNNN', 'PYTHONN', 'PYTHON']
# -------------------------------
In [27]: pat=r'PY[TH]ON'
In [28]: p=re.compile(pat)
In [29]: p.findall("PYTON PYHON PYTHON")
Out[29]: ['PYTON', 'PYHON']
# ------------------------------
# [^5] 将匹配除 '5' 以外的字符
# 那这里就是 匹配除了 TH以外的字符 中括号这个位置
# ? 表示0 次或者 1次
In [30]: pat=r'PY[^TH]?ON'
In [31]: p=re.compile(pat)
In [34]: p.findall("PYON PYaON PYTHON PYcON PYTON PYAON")
Out[34]: ['PYON', 'PYaON', 'PYcON', 'PYAON']
# -------------------
In [35]: pat='PY{0,3}N'
# 图片中的写法 {:3} 这种写法 不生效 无法匹配
In [36]: p=re.compile(pat)
In [37]: p.findall("PYNPYNPYNPYN PYYN PYYYN PYYYYYN")
Out[38]: ['PYN', 'PYN', 'PYN', 'PYN', 'PYYN', 'PYYYN']
In [37]: pat=r'^[A-Za-z]+$' # 既然 + 是 1 次或者无限次
# 那么 我们也可以改为 ? 0次 或者 1次 那就只匹配 1个 字母了
# 字母
In [38]: p=re.compile(pat)
In [39]: p.match("adsfadfasd")
Out[39]: <_sre.SRE_Match object; span=(0, 10), match='adsfadfasd'>
In [40]: p.match("adsfadfasdADSFAKSD...")
In [41]: p.match("adsfadfasdADSFAKSD")
Out[41]: <_sre.SRE_Match object; span=(0, 18), match='adsfadfasdADSFAKSD'>
# ------------------------------
# 字母和数字
In [43]: pat=r'^[A-Za-z0-9]+$'
In [44]: p=re.compile(pat)
In [46]: p.search("dasfasdfsdf23141")
Out[46]: <_sre.SRE_Match object; span=(0, 16), match='dasfasdfsdf23141'>
# --------------------------------
# 整数
In [49]: pat=r'^-?\d+$'
In [50]: p=re.compile(pat)
In [51]: p.search("123")
Out[51]: <_sre.SRE_Match object; span=(0, 3), match='123'>
In [52]: p.search("+123")
In [53]: p.search("-123")
Out[53]: <_sre.SRE_Match object; span=(0, 4), match='-123'>
In [54]: p.search("-123.2")
# ------------------
# 正整数
In [56]: pat=r'^[0-9]*[1-9][0-9]*'
In [57]: p=re.compile(pat)
In [58]: p.search("31434")
Out[58]: <_sre.SRE_Match object; span=(0, 5), match='31434'>
In [59]: p.search("031434")
Out[59]: <_sre.SRE_Match object; span=(0, 6), match='031434'>
In [60]: p.search("0031434")
Out[60]: <_sre.SRE_Match object; span=(0, 7), match='0031434'>
In [61]: p.search("-31434")
# --------------------------
# 邮编
In [62]: pat=r'[1-9]\d{5}'
In [63]: p=re.compile(pat)
In [64]: p.search("314200")
Out[64]: <_sre.SRE_Match object; span=(0, 6), match='314200'>
In [65]: p.search("31420000")
Out[65]: <_sre.SRE_Match object; span=(0, 6), match='314200'>
In [66]: p.search("00031420000")
Out[66]: <_sre.SRE_Match object; span=(3, 9), match='314200'>
# ------------------------
In [68]: pat=r'[\u4e00-\u9fa5]'
# 中文字符
In [69]: p=re.compile(pat)
In [70]: p.search("把酒问青天")
Out[70]: <_sre.SRE_Match object; span=(0, 1), match='把'>
In [71]: p.findall("把酒问青天")
Out[71]: ['把', '酒', '问', '青', '天']
# ------------------------------------
# 国内电话号码
In [75]: pat=r'\d{3}-\d{8}|\d{4}-\d{7}'
In [76]: p=re.compile(pat)
In [77]: p.search("021-6891336")
In [78]: p.search("021-68913536")
Out[78]: <_sre.SRE_Match object; span=(0, 12), match='021-68913536'>
# -------------------------------------
# 匹配手机号码
import re
# pattern='\d\d\d\d\d\d\d\d\d\d\d'
pattern='1[35789]\d\d\d\d\d\d\d\d\d'
pattern='1[35789]\d{9}' # 和上面的式子 是不是等价呢? 是的。
s='13456788765'
o=re.match(pattern,s)
print(o)
#电话号码 区号-座机号 010-3762266 0342-8776262
In [12]: import re
In [13]: pattern='1[35789]\d{9}'
In [14]: s='13456788765'
...: o=re.match(pattern,s)
In [15]: o
Out[15]: <_sre.SRE_Match object; span=(0, 11), match='13456788765'>
In [2]: import re
In [3]: pat='\d+.\d+.\d+.\d+'
In [4]: p=re.compile(pat)
# 很明显
# ip 地址 没有 大于 255 的
# 且长度 是 1 到 3
In [5]: p.findall("255.255.255.255 3333.333.333.333")
Out[5]: ['255.255.255.255 ', '3333.333.333.333']
In [14]: pat='\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}'
In [15]: p=re.compile(pat)
# 这个很明显 也是有点问题的
In [16]: p.findall("255.255.255.255 3333.333.333.333")
Out[16]: ['255.255.255.255', '3333.333.333']
In [29]: pat=r'(([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5]).){3}([1-9]?\d|1\d{
...: 2}|2[0-4]\d|25[0-5])'
In [30]: p=re.compile(pat)
In [34]: p.fullmatch("255.255.255.255")
Out[34]: <_sre.SRE_Match object; span=(0, 15), match='255.255.255.255'>
# fullmatch 我个人感觉 和 match("^33.33.33.33$") 比较类似。
# 感兴趣的可以去 测试一波
In [36]: p.fullmatch("33.33.33.33") # fullmatch 全匹配
Out[36]: <_sre.SRE_Match object; span=(0, 11), match='33.33.33.33'>
其他简单例子
# 1. 验证手机号码
text = "12567347199"
ret = re.match('1[34578]\d{9}', text)
print(ret.group())
# 2. 验证邮箱
text = "pis1@qq.com"
ret = re.match('\w+@[a-z0-9]+\.[a-z]+', text)
print(ret.group())
# 3. 验证 url 协议
text = "https://www.baidu.com/"
ret = re.match('(http|https|ftp)://[^\s]+', text) # 竖线 就是 或的 意思
print(ret.group())
# 4. 验证身份证
text = "51152319930228159x"
ret = re.match('\d{17}[\dxX]', text)
print(ret.group())
import re
print('------案例1------')
#匹配出一个字符串首字母为大写字符,后边都是小写字符,这些小写字母可有可无
pattern='[A-Z][a-z]*'
s='Hello'
s='HEllo'
o=re.match(pattern,s)
print(o)
print('------案例2------')
#匹配出有效的变量名 (字母 、数字 下划线 ,而且数字不能开头)
# pattern='[a-zA-Z_][a-zA-Z0-9_]*'
pattern='[a-zA-Z_]\w*'
s='userName'
s='age'
s='a'
s='_qwe'
# s='3er'
o=re.match(pattern,s)
print(o)
print('-------案例3----------')
#匹配出1-99直接的数字
pattern='[1-9]\d?'
s='2'
s='99'
s='100'
s='0'
o=re.match(pattern,s)
print(o)
print('----------案例4--------------')
#匹配出一个随机密码8-20位以内 (大写字母 小写字母 下划线 数字)
pattern='\w{8,20}'
s='123456789'
s='abc123qwe_'
s='1234567#'
o=re.match(pattern,s)
print(o)
常用操作符(.
,*
,{}
,?
,+
,^
…)
常用匹配字符串
# 重复数量符号
'''
* :0次或多次
? :0次或1次
+ :至少1次
{m} :重复m次
{m,n} :重复m到n次
{m} :至少重复m次
{m,} :长度的大于等于,
{,n} :小于等于
'''
# 常用的 匹配字符串
'''
. 匹配任意一个字符(除了\n)
[] 匹配列表中的字符
\w 匹配字母、数字、下划线,即a-z,A-Z,0-9,_
\W 匹配不是字母、数字、下划线
\s 匹配空白字符,即空格(\n,\t)
\S 匹配不是空白的字符
\d 匹配数字,即0-9
\D 匹配非数字的字符
'''
这里也有一些特殊字符的展示
比如 十六进制 Unicode
码 \u0000:\uFFFF
ASCII
码 \x00:\xFF
,
-
中文
字符的Unicode
范围\u4e00-\u9fa5
-
ascii
只能匹配 英文的。 范围为0- 255
一共256
个字符
关于控制字符 \cA-\cZ
对应的是 ascii
中 1-26
的控制字符 。但是 python
不支持 \cA
这种写法
所以不建议 使用 建议使用 十六进制码
或者 \t
这种写法(前提是那个字符有类似的写法)
演示
看完这个应该就能理解我想说的是什么了。
import re
str_="""
中国牛逼
2020-12-12
2020年12月4日19:47:07
"""
pat=r'[\n]'
pat1=r'[\x0A]'
re.findall(pat,str_)
re.findall(pat1,str_)
匹配某个字符串
# match, 匹配某个字符串
text = 'hello'
ret = re.match('he', text)
# match 只会匹配前面的字符 ahello 就匹配不到了
print(ret.group()) # group 把提匹配到的字符串提取出来
.
点 , 匹配符任意的字符
# 点,匹配符任意的字符
text = 'hello'
ret = re.match('.', text) # 但是只能匹配一个字符,但是 不能匹配换行符\n
print(ret.group())
任意字符不包括换行符
真正的任意字符可以写成 多种方式 [\w\W]
[\s\S]
[\d\D]
或者 使用 flags
标志 re.S
任意的数字 \d
# 任意的数字 \d (0-9)
text = "1"
ret = re.match('\d', text)
print(ret.group())
\s
匹配空白的字符
# \s 匹配空白的字符(例如:\n \r \t ,空格)
text = " a b"
ret = re.match('\s', text)
print(ret.group())
任意的非数字 \D
# 任意的非数字 \D
text = "+a"
ret = re.match('\D', text)
print(ret.group())
\w
匹配的是 a-z 和A-z 以及数字0-9和下划线
# \w 匹配的是 a-z 和A-z 以及数字0-9和下划线
text = "ab"
ret = re.match('\w', text)
print(ret.group())
\W
匹配 大小写字母 数字 和 下划线 以外的字符
# \W 与 \w 相反 匹配的
text = "+ab"
ret = re.match('\W', text)
print(ret.group())
*
匹配多个字符
# 匹配多个字符
# * 星号可以匹配 0个 或者任意多个 字符
text = "abdc"
ret = re.match('\d*', text) # 这个 '\d*' 匹配任意多个数字
print(ret.group())
# + 加号 匹配一个或者多个字符
text = "+abdc"
# 这个 '\w+'' 匹配一个以上 a-z 和A-z 以及数字0-9和下划线 组成的 字符串
ret = re.match('\w+', text) # 因为 是从开头开始匹配 ,所以这里会报错 因为开头 匹配不到
print(ret.group())
import re
print('--------*的使用------------')
pattern='\d*'
s='123qwe'
s='123456qwe'
s='qwe'
o=re.match(pattern,s)
print(o)
?
问号 匹配一个或者0个字符
# ? 问号 匹配一个或者0个字符
text = "abdc+"
ret = re.match('\w?', text)
print(ret.group())
print('--------?的使用------------')
pattern='\d?'
s='123qwe'
s='1qwe'
s='123456qwe'
s='qwe'
o=re.match(pattern,s)
print(o)
{m}
匹配m个字符
# {m}匹配m个字符
text = "abdc+"
ret = re.match('\w{2}', text) # 匹配两个字符
print(ret.group())
print('---------{m}-----------')
pattern='\d{2}'
pattern='\d{3}'
pattern='\d{4}'
s='123qwe'
o=re.match(pattern,s)
print(o)
{m,n}
匹配 m到n个字符
# {m,n}匹配m到n个字符
text = "abdcdanmd;a"
ret = re.match('\w{1,5}', text)
print(ret.group())
print('---------{m,n}-----------')
pattern='\d{2,5}'
s='123qwe'
s='123456qwe'
s='qwe'
o=re.match(pattern,s)
print(o)
{m,} {,n}
实现 长度的大于等于, 小于等于
print('---------{m,}-----------')
pattern='\d{2,}'
s='123qwe'
s='123456qwe'
s='qwe'
o=re.match(pattern,s)
print(o)
# 表示 空字符串。长度为 0 的字符串。
s = ''
o1 = re.match(r'^$', s)
print(o1) # 有匹配结果,匹配到空字符串
s = '1'
print(o1) # 无匹配结果,返回 None
- 指定开放区间,省略第2个值,保留逗号。例如
a{4, }
匹配4个或更多个连续的字符a。
脱字号 ^
以 …开始,
# 脱字号 '^' 以 ...开始,
# 放在中括号[]里面 是取反的意思
text = "hello.py"
ret = re.search('^h\w*\.py$', text) # match 是从开始去匹配 和 脱字号 是一样的功能
print(ret.group())
'$'
以…结尾
# '$' 以...结尾
text = "pis1@163.com"
ret = re.match('\w+@163.com$', text) # match 是从开始去匹配 和 脱字号 是一样的功能
print(ret.group())
'|'
匹配多个字符串或者表达式
# `'|' ` 匹配多个字符串或者表达式 或者的 意思 要么 的意思
text = "http"
ret = re.match('(http|https|ftp)$', text) # match 是从开始去匹配 和 脱字号 是一样的功能
print(ret.group())
# 匹配多个字符串
import re
pattern='aa|bb|cc'
s='aa'
o=re.match(pattern,s)
print(o)
s='bb'
o=re.match(pattern,s)
print(o)
s='my name is cc'
o=re.search(pattern,s)
o=re.match(pattern,s)
print(o)
print('匹配0-100之间所有的数字')
#匹配0-100之间所有的数字 0-99|100
pattern=r'[1-9]?\d$|100$'
s='1'
s='11'
s='99'
s='100'
s='1000'
o=re.match(pattern,s)
print(o)
关于 !
和 ^
以及 $
搭配使用
(^|\\s)
就代表 可以是 以 ''
就是没有字符开始 或者 \s
空白字符开始 的 字符
同理 $
这就是 以没有""
结尾 或者 空字符结尾
# import re
In [51]: reg
Out[51]: '(^|\\s){}(\\s|$)'
In [52]: reg2
Out[52]: '(^|\\s){}'
In [57]: re.search(reg2.format('classname'),'c classname b'
...: )
Out[57]: <re.Match object; span=(1, 11), match=' classname'>
In [58]: re.search(reg2.format('classname'),'classname c b'
...: )
Out[58]: <re.Match object; span=(0, 9), match='classname'>
In [59]: re.search(reg2.format('classname'),'a b classname'
...: )
Out[59]: <re.Match object; span=(3, 13), match=' classname'>
In [60]: reg2
Out[60]: '(^|\\s){}'
In [62]: reg
Out[62]: '(^|\\s){}(\\s|$)'
In [63]: re.search(reg.format('classname'),'a b classname')
...:
Out[63]: <re.Match object; span=(3, 13), match=' classname'>
In [64]: re.search(reg.format('classname'),'classname c b')
...:
Out[64]: <re.Match object; span=(0, 10), match='classname '>
In [65]: re.search(reg.format('classname'),'c classname b')
...:
Out[65]: <re.Match object; span=(1, 12), match=' classname '>
[ ]
组合的方式
# [ ] 组合的方式 ,只要,满足中括号 中的字符,就可以匹配
text = "a"
ret = re.match('[a1]', text) # 匹配 a和 1
print(ret.group())
8.1
text = "0731-88888888"
# 特殊字符 需要 -前面转义 加一个\ \d是数字匹配 写一个 + 加号 就是匹配到 多个字符
ret = re.match('[\d\-]+', text)
print(ret.group())
# 8.2 中括号 代替 \d 以及 反斜杠 \w
text = "1213"
ret = re.match('[^0-9]+', text) # 这个 ^0-9 是 匹配非0-9的字符 前面加了一个脱字号
print(ret.group())
# 8.2 中括号 代替 以及 反斜杠 \w
text = "1213"
ret = re.match('[a-zA-Z0-9_]', text) # 这个 ^0-9 是 匹配非0-9的字符
print(ret.group())
# 8.2 中括号 代替 以及 反斜杠 \W
text = "*"
ret = re.match('[^a-zA-Z0-9_]', text) # 这个 ^0-9 是 匹配非0-9的字符
print(ret.group())
|
和[ ]
两者之间的差异
# 择一匹配符 和 列表使用差异
import re
# pattern=r'[xyz]'
# s='y'
# o=re.match(pattern,s)
# print('使用列表[]:',o)
#
# pattern=r'x|y|z'
# s='y'
# o=re.match(pattern,s)
# print('择一匹配符|:',o)
# print('字符集([])和择一匹配符(|)的用法,及它们的差异')
# pattern=r'[ab][cd]'
# s='ac'
# s='ab'
# o=re.match(pattern,s)
# print(o)
# pattern=r'ab[cd]'
# # s='ab'
# # s='abc'
# s='abd'
# o=re.match(pattern,s)
# print(o)
pattern='ab|cd'
# s='abc'
# s='abd'
# s='cd'
s='ad'
s='ac'
o=re.match(pattern,s)
print(o)
+
号 的使用
print('--------+的使用------------')
pattern='\d+'
# s='123qwe'
# s='1qwe'
# s='123456qwe'
s='qwe'
o=re.match(pattern,s)
print(o)
转义字符的使用
当然 我们也可以使用 raw
原生字符 s=r'\t123'
类似这样的语法 会经常 看到。
# 转义字符的使用
print('d:\\a\\b\\c')
print('\nabc')
print('\\nabc')
print('\t123')
print('\\t123')
import re
s='\\t123'
# pattern='\\\\t\d*'
pattern=r'\\t\d*'
o=re.match(pattern,s)
print(o)
s='\\\\t123'
# pattern='\\\\\\\\t\d*'
pattern=r'\\\\t\d*'
o=re.match(pattern,s)
print(o)
# 转义字符 和 原生字符串
text = "apple price is $299"
ret = re.search("\$\d+", text) # 提取价格 \ 转义 \$ 只想 让他作为 普通字符串
print(ret.group())
# 原生字符串
text = "\\n" # python 中的 转义字符 把 换行符 转换成一个 普通反斜杠
text = r"\n" # 前面加一个r 就是原生的意思 r 就是 raw 原生的意思 别的 正则里面也可以使用
print(text)
# 反斜杠 正则和 python 的 \ 反斜杠 都是 转义 ,所以 想要打印出反斜杠 需要4 个反斜杠
text = '\c' # 这里在python 语言中 '\\n'='\n'
# python中\\\\c => \\c
# 正则中 \\c= > \c
# ret = re.match('\\\\c', text) # 转义
ret = re.match(r'\\c', text) # 原生字符串的方式
print(ret.group())
常用方法
常用查询,主要功能函数
re.search
# search 方法的使用
import re
pattern='hello'
s='hello python'
# m=re.search(pattern,s)
m=re.match(pattern,s)
print(m)
print(m.group())
print('-------macth和search的区别----------')
pattern='love'
s='I love you'
m=re.match(pattern,s)
print('使用match进行匹配',m)
o=re.search(pattern,s)
print('使用search进行匹配',o) # search 是搜索 mat是从开始位置匹配
In [26]: pattern='love'
...: s='I love you'
...: m=re.match(pattern,s)
In [27]: m
In [28]: o=re.search(pattern,s)
In [29]: o
Out[29]: <_sre.SRE_Match object; span=(2, 6), match='love'>
re.match
# match 方法的使用
import re
s='hello python'
pattern='hello'
o=re.match(pattern,s)
# -----------------
print(o)
print(dir(o))
print(o.group()) #返回匹配的字符串
print(o.span())
print(o.start())
# ---------------------
print('flags参数的使用')
s='hello python'
pattern='Hello'
o=re.match(pattern,s,flags=re.I)
# re.I
# re.IGNORECASE 这两个是一样的。
# 都是忽略大小写
print(o)
print(o.group())
# -------------------
In [3]: print(o)
<_sre.SRE_Match object; span=(0, 5), match='hello'>
In [4]: print(dir(o))
['__class__', '__copy__', '__deepcopy__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'end', 'endpos', 'expand', 'group', 'groupdict', 'groups', 'lastgroup', 'lastindex', 'pos', 're', 'regs', 'span', 'start', 'string'] # 这里是这个 match 对象的属性
In [5]: print(o.group()) #返回匹配的字符串
hello
In [6]: print(o.span()) # 匹配到的字符串的 索引范围
(0, 5)
In [7]: print(o.start()) # 匹配到的字符的 开始位置
0
In [8]: print('flags参数的使用')
flags参数的使用
In [9]: s='hello python'
...: pattern='Hello'
...: o=re.match(pattern,s,flags=re.I)
# re.I
# re.IGNORECASE 这两个是一样的。
# 都是忽略大小写
In [10]:
In [10]: print(o)
<_sre.SRE_Match object; span=(0, 5), match='hello'>
In [11]: print(o.group())
hello
re.findall
import re
print('---------findall-------------')
s='first 1 second 2 third 3'
pattern=r'\w+'
result=re.findall(pattern,s)
print(result)
re.split
import re
print('----------split-------------')
s='first 11 second 22 third 33'
pattern=r'\d+'
result=re.split(pattern,s)
print(result)
result=re.split(pattern,s,maxsplit=2)
print(result)
# split 分割函数
text = "hello&world ni hao"
ret = re.split('[^a-zA-Z]', text) # 以非英文字母为分割 符号
print(ret)
re.finditer
import re
print('---------finditer-------------')
s='first 1 second 2 third 3'
pattern=r'\w+'
result=re.finditer(pattern,s)
print(result)
for i in result:
print(i.group(),end='\t')
print()
re.sub
import re
print('--------sub-------------')
phone='2004-959-559 # 这是一个国外电话号码'
#将phone中的注释去掉
pattern=r'#.*$'
result=re.sub(pattern,'',phone)
print('sub:',result)
pattern=r'#\D*'
result=re.sub(pattern,'',phone)
print('sub:',result)
subn
执行与相同的操作sub()
,但返回一个元组 (new_string, number_of_subs_made)
.
import re
phone='2004-959-559 # 这是一个国外电话号码'
#将phone中的注释去掉
pattern=r'#.*$'
print('---------subn-----------')
result=re.subn(pattern,'',phone)
print(result)
print(result[0])
print(result[1])
re.compile
import re
print('---------compile------------')
s='first123 line'
pattern=r'\w+'
regex=re.compile(pattern)
o=regex.match(s)
print(o)
# compile 函数
text = "the number is 20.50"
# 两个功能
# 功能1 正则表达 编译起来存在内存中
# r = re.compile('\d+\.?\d*') # 用 compile 编译 保存到对象里
# ret = re.search(r, text) # 这里直接传入对象 r 就可以了
# print(ret.group()) # 这样子 效率比较高
# 功能2 为正则写注释 这是一个好习惯 一定要写注释 方便以后 看 以及调试
r = re.compile(r"""
\d+ # 小数点前面的数
\.? # 小数点本身
\d* # 小数点后面的数字
""", re.VERBOSE)
ret = re.search(r, text)
print(ret.group())
# 查找 所有空行
'^\s(?=\r?$)\n'
rr = re.compile(r"""
^\s # 以空白字符开头
(?=\r?$)# 回车
\n # 换行
""", re.VERBOSE)
# re.DOTALL 匹配所有的字符
re.escape(pattern) 处理转义字符
re.escape(pattern)
在中转义特殊字符 模式 . 如果要匹配可能包含正则表达式元字符的任意文本字符串,则此选项非常有用。例如:
>>> print(re.escape('http://www.python.org'))
http://www\.python\.org
>>> legal_chars = string.ascii_lowercase + string.digits + "!#$%&'*+-.^_`|~:"
>>> print('[%s]+' % re.escape(legal_chars))
[abcdefghijklmnopqrstuvwxyz0123456789!\#\$%\&'\*\+\-\.\^_`\|\~:]+
>>> operators = ['+', '-', '*', '/', '**']
>>> print('|'.join(map(re.escape, sorted(operators, reverse=True))))
/|\-|\+|\*\*|\*
常用方法(函数)sub
案例
import re
# 实际的案例 替换 函数
html = '''
<dd class="job_bt">
<h3 class="description">职位描述:</h3>
<div class="job-detail">
<p>岗位职责:</p>
<p>1、完成对复杂网站的数据抓取和交互模拟;</p>
<p>2、通过各种渠道或方式对相关网站进行抓取;</p>
<p>3、不断完善并维护相关网站的抓取,使之稳定运行,核心逻辑必须有单元测试;</p>
<p>4、善于灵活运用各种非爬虫技术解决爬虫相关问题;</p>
<p>5、随时响应并解决突发问题;</p>
<p>6、完成领导交办的其他工作。</p>
<p><br></p>
<p>任职要求:</p>
<p>1、本科以上学历,三年以上网站抓取经验,有电商网站、秒杀相关抓取经验;</p>
<p>2、有较强的网站分析能力,熟知各种反爬措施及相关解决办法</p>
<p>技能要求;</p>
<p>3、熟练使用eventlet、gevent、requests、selenium等技术实现高并发稳定抓取;</p>
<p>4、熟练使用消息队列(MQ)、celery等异步框架实现分布式任务处理;</p>
<p>5、熟知HTTP、TCP、Socket等底层知识;</p>
<p>6、熟练掌握Fiddler、Http debugger等抓捕工具;</p>
<p>7、熟悉MySQL、MongoDB基本使用;</p>
<p>8、熟悉Scapy,熟悉Javascript,有一定的分析能力;</p>
<p>9、能使用mock进行单元测试;</p>
<p>10、善于沟通、有团队协作精神。</p>
<p><br></p>
<p>我们的团队成员都是80后、90后,我们是充满激情和干劲的团队,我们是有梦想有追求的团队……</p>
<p>如果你有满腔热忱,如果你不想碌碌无为,如果你想通过自己的努力成为合伙人……</p>
<p>来吧!朋友,加入我们,我们会给你释放梦想的平台,我们会让你的美梦成真……</p>
<p>期待有为的你加入!!!</p>
<p> </p>
<p>为了让我们的小伙伴能够快乐、健康的在一起为了梦想而努力,我们提供了以下多种福利及文化活动:</p>
<p>1、每天工作8小时,弹性工作时间;</p>
<p>2、公司年度健康体检,小伙伴在为公司默默奉献的同时,公司也时刻关注着他们的健康。</p>
<p>3、量身定制的培训计划,让员工在我们细致入微的帮助下更快的融入团队。</p>
<p>4、丰富的企业文化活动:</p>
<p>Ø 每天:美味的零食和饮品;</p>
<p>Ø 每两周:组织大家去打乒乓球、羽毛球,小伙伴的健康是我们一直关注的;</p>
<p>Ø 每月:家人生日会(给每位寿星唱着生日快乐歌,分享美味可口的蛋糕,尽享温馨时刻);</p>
<p>Ø 季度:团队建设、拓展活动;</p>
<p>Ø 年度:大型年会(辛苦了一年的汇游科技家人,一起收获一起分享)。</p>
<p>5、每年1次调薪,两次丰厚的绩效奖金,付出与回报永远成正比哦。</p>
<p>6、节日礼品、生日礼品、结婚生子礼金等。</p>
<p>7、每天午餐补助,每月全勤奖励。</p>
<p>…………</p>
<p> </p>
<p> </p>
<p>汇游科技祝您面试成功!</p>
</div>
</dd>
'''
ret = re.sub('<.+?>', '', html) # 非贪婪 模式 ,把 非标签的数据替换掉了
print(ret)
re
匹配到的对象
比如match
或者search
匹配到 的对象 也就是 这些函数的 返回值
可以这样理解。
<_sre.SRE_Match object; span=(0, 11), match='33.33.33.33'>
这个就是一个返回对象 。
match
对象
匹配对象
返回对象的常用属性
返回对象的常用方法
贪婪模式和非贪婪模式
re 默认是贪婪模式
如何非贪婪模式?
*?
, +?
, ??
这些符号 就代表非贪婪 模式 (也叫最小匹配操作符)
比如 你使用 (.*?)
匹配任意字符 但是 是非贪婪 模式 。 只匹配最少的数据。
# 贪婪模式 与 非贪婪模式
# 贪婪模式就是会 尽量多的 字符'\d+'
# 非贪婪模式'\d+?' 匹配到 +的 最小的 条件 # + 表示(1个或者多个匹配)
text = "0123456"
ret = re.search('\d+?', text) # match 是从开始去匹配 和 脱字号 是一样的功能
print(ret.group())
text = "<h1>标题1</h1>"
ret = re.search('<.+?>', text) # 非贪婪模式 问号 去掉 就是 贪婪模式
print(ret.group())
# 小案例 匹配0-101之间的数字
# 可以出现的是 1 2 3 9 100 88
# 不可以出现的是 09 101
# 有三种情况 1位1-9 2位10-99 3位 100
for text in range(1, 102):
text1 = str(text)
ret = re.search("^[1-9]\d?$|100$", text1)
print(ret.group())
关于分组
(...)
匹配圆括号内的任何正则表达式,并指示组的开始和结束;组的内容可以在执行匹配后检索,稍后在字符串中与 \number
特殊顺序,如下所述。匹配文字 '('
或 ')'
使用 \(
或 \)
或将它们括在字符类中: [(]
, [)]
.
\number
匹配同一号码组的内容
。组从1
开始编号。例如, (.+) \1
'the the'
或 '55 55'
,但不匹配 'thethe'
(注意组后的空格)。
# (ab) 将括号中的字符作为一个分组
# \num 引用分组num匹配到的字符串
In [99]: re.match(r"(.)\1+","66555")
Out[99]: <_sre.SRE_Match object; span=(0, 2), match='66'>
# 注意这种形式 无法 匹配长度 为 1 的 字符
# 因为 这是 匹配同一 号码组的 内容。
# 进去之后先被分组了 一个数字。
# 然后和他同一号码组的 数字 就没有了
# 不信的话。 分组之后 组里面 就只有一个 数字。 可以 看看
# --------------------------------
In [100]: re.match(r"(.+)\1","thethe")
Out[100]: <_sre.SRE_Match object; span=(0, 6), match='thethe'>
In [101]: re.match(r"(.+) \1","thethe") # 这个没有输出
# 注意 组括号 和 \number 之间的空格
In [102]: re.match(r"(.+) \1","the the")
Out[102]: <_sre.SRE_Match object; span=(0, 7), match='the the'>
()
分组 \num
别名
import re
# 示例 1 匹配座机号码 使用 ( ) 括号 分组
print('匹配座机号码')
# 匹配座机号码 区号{3,4}-电话号码{5,8} 010-43222 0432-447727
pattern=r'\d{3,4}-[1-9]\d{4,7}$'
pattern=r'(\d{3,4})-([1-9]\d{4,7}$)'
s='010-786545'
o=re.match(pattern,s)
print(o)
print(o.group())
print(o.group(1))
print(o.group(2))
# print(o.groups())
# print(o.groups()[0]) # 这样子 group() 返回的是字符串 所以这种方式 就是类似元组 切片 索引访问 字符串。
# print(o.groups()[1])
print('匹配出网页标签内的数据')
# 示例 2 分组示例 \num
# pattern=r'<.+><.+>.+</.+></.+>'
pattern=r'<(.+)><(.+)>.+</\2></\1>'
s='<html><head>head部分</head></html>'
# s='<html><title>head部分</head></body>'
o=re.match(pattern,s)
print(o)
# ( ) \1
# 正确示范,()有分组作用,正则表达式中\1可以取到分组的第一个
import re
html_str = "<h1>hahaha</h1>"
ret = re.match(r"<(\w*)>.*</\1>", html_str)
print(ret.group())
# ( ) \1
# 正确示范,()有分组作用,正则表达式中 \1 和 \2取值顺序
import re
html_str = "<body><h1>hahaha</h1></body>"
ret = re.match(r"<(\w*)><(\w*)>.*</\2></\1>", html_str)
print(ret.group())
# 示例 3 分组起别名
# (?p<name>) 分别起组名
# (?p=name) 引用别名为name分组匹配到的字符串
# 示例html标签 .+ 匹配 起别名
# <(?P<k_html>.+)>
#<body><h1><div><div></div></div></h1></body>
print('(?P<name>) 分别起组名')
pattern=r'<(?P<k_html>.+)><(?P<k_head>.+)>.+</(?P=k_head)></(?P=k_html)>'
s='<html><head>head部分</head></html>'
# s='<html><title>head部分</head></body>'
o=re.match(pattern,s)
print(o)
通过观察可以发现 取了别名
就有了 groupdict
了
# -------------------------------
(?P<name>) #命名的格式 (注意P是大写的)
(?P=name) #取值的格式
#
import re
html_str = "<body><h1>hahaha</h1></body>"
ret = re.match(r"<(?P<p1>\w*)><(?P<p2>\w*)>.*</(?P=p2)></(?P=p1)>", html_str)
print(ret.group())
import re
# 分组
text = "apple's price $99, orange's price $10"
ret = re.search('.*(\$\d+).*(\$\d+)', text) # 将整个字符串提取出来括号里是分组的意思
print(ret.group()) # 整个正则表达式 就是一个 大的分组,可以写0或者不写 都是可以的
print(ret.group(1)) # 第一个分组
print(ret.group(2)) # 第二个分组
print(ret.group(1, 2)) # 两个分组 拿出来
print(ret.groups()) # 所有 的子分组 都拿出来
(...)\number
# (\number)
In [101]: a='WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB'
In [102]: a
Out[102]: 'WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB'
In [103]: re.sub(r"(.)\1+",lambda x:str(len(x.group(0)))+ x.group(1),a)
Out[103]: '12WB12W3B24WB'
In [109]: re.sub(r"(.)\1+",lambda x:print(x),a)
<_sre.SRE_Match object; span=(0, 12), match='WWWWWWWWWWWW'>
<_sre.SRE_Match object; span=(13, 25), match='WWWWWWWWWWWW'>
<_sre.SRE_Match object; span=(25, 28), match='BBB'>
<_sre.SRE_Match object; span=(28, 52), match='WWWWWWWWWWWWWWWWWWWWWWWW'>
Out[109]: 'BB'
group
都是 从 1
开始编码
group(0)
等价于 group()
返回整个 匹配 。
groups
返回一个包含匹配的所有子组的元组,从1到模式中的所有组。这个 default 参数用于没有参与匹配的组;它默认为 None .
In [263]: m = re.match(r"(\d+)\.(\d+)", "24.1632")
In [264]: m.groups()
Out[264]: ('24', '1632')
关于分组的 一些实际 例子
分组的反向引用 ( 就是那个 \1
)
import re
import requests
pat="<(\w+)>(.+)<\/\1>" # 基本套路 不过对于一些复杂的 html 标签无法 提取
res=requests.get("http://www.baidu.com")
res.encoding='utf-8'
html=res.text
pat=r"<(head)>(.+)</\1>" # 稍加 修改
re.findall(pat,html)
# ----------------------------
# 返回结果
# [('head',
#'<meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title>')]
pat=r"<(div)\s*.*?>(.+)</\1>" # 再次修改
re.findall(pat,html)
# 返回结果
# [('div',
# ' <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn"></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=http://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write(\'<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=\'+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ \'" name="tj_login" class="lb">登录</a>\');</script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>©2017 Baidu <a href=http://www.baidu.com/duty/>使用百度前必读</a>&nbsp; <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a> 京ICP证030173号 <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> ')]
pat=r"<(\w+)\s*.*?>(.+)</\1>" # pat="<(\w+)>(.+)<\/\1>" 完成我在一开始想用这个操作的事情。
re.findall(pat,html)
# 返回结果
#[('html',
# ' <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn"></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新闻</a> <a href=http://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地图</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>视频</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>贴吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登录</a> </noscript> <script>document.write(\'<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=\'+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ \'" name="tj_login" class="lb">登录</a>\');</script> <a href=//www.baidu.com/more/ name=tj_briicon class=bri style="display: block;">更多产品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>关于百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>©2017 Baidu <a href=http://www.baidu.com/duty/>使用百度前必读</a>&nbsp; <a href=http://jianyi.baidu.com/ class=cp-feedback>意见反馈</a> 京ICP证030173号 <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> ')]
一些运行效果
常用的 flags
re.A
re.ASCII
制作 \w , \W , \b , \B , \d , \D , \s 和 \S
只执行ASCII匹配,而不是完全Unicode匹配。这只对Unicode
模式有意义,而对于字节模式则被忽略。对应于内联标志 (?a)
.
请注意,为了向后兼容, re.U
标志仍然存在(及其同义词 re.UNICODE 及其嵌入的对应项 (?u)
,但在python 3中这些是多余的,因为字符串的匹配默认为Unicode
(字节不允许使用Unicode匹配)。
re.DEBUG
显示有关已编译表达式的调试信息。没有对应的内联标志。
re.I
re.IGNORECASE
执行不区分大小写的匹配; 对应于内联标志 (?i)
.
re.M
re.MULTILINE
指定时,模式字符 '^'
匹配字符串的开头
和每行的开头
(紧跟每行换行符);以及模式字符 $
匹配字符串的结尾和每行的结尾
(紧接着每行换行符的前面)。默认情况下, '^'
仅在字符串的开头匹配,并且 '$'
只在字符串的末尾,在字符串末尾的换行符(如果有)之前。对应于内联标志 (?m)
.
其实一句话 就是 换行符为边界
比如 22\n3322\n3322\n33
如果我要获取 以某某开头的两位数字字符。 以换行符为边界。 那就是 22 33 33 33
可以理解为 行首 行尾 的概念。
而不是字符串的首尾。
如果flags 用 re.M 但是想要 获取字符串首部
那就是 \A
需要写在开头 ,获取字符串尾部
是 \Z
需要写在后面
import re
pat=r"(?m)^\d{2}"
str_="22\n3322\n3322\n33"
re.findall(pat,str_)
关于 \A
\Z
import re
pat=r"(?m)^\A\d{2}"
str_="22\n3322\n3322\n33"
re.findall(pat,str_)
pat=r"(?m)^\d{2}\Z"
re.findall(pat,str_)
re.S
re.DOTALL
使'.'
特殊字符完全匹配任何字符
,包括换行符
;如果没有此标志, '.'
会匹配任何东西 除了 换行符
对应于内联标志 (?s)
.
re.X
re.VERBOSE
此标志允许您编写看起来更好、更可读的正则表达式,方法是允许您直观地分隔模式的逻辑部分并添加注释
。
指定多个 flags
的方式
re.I | re.M
用 |
表达符 表示 flags 被设置为了 re.I
和 re.M
或者使用内联的方式 (?im)
并且这个 标志要写在 最开始的位置。 否则会报 警告信息
import re
str_="""
One1
oNe2
onE3
noe4
"""
pat=r"^one\w+"
pat1=r"(?im)one\w+"
re.findall(pat,str_)
re.findall(pat1,str_)
re.findall(pat,str_,flags=re.I|re.M)
re.findall(pat,str_,flags=re.I)
re.findall(pat,str_,flags=re.M)
一些不常见的匹配符号
(?P=name)
(?P< name >)
- 命名的格式 (注意P是大写的)
(?P=name)
- 取值的格式
对命名组的后向引用
;它与先前命名组匹配的任何文本匹配 name .
<(?P<p1>\w*)><(?P<p2>\w*)>.*</(?P=p2)></(?P=p1)>
以这为 例子
import re
html_str = "<body><h1>hahaha</h1></body>"
ret = re.match(r"<(?P<p1>\w*)><(?P<p2>\w*)>.*</(?P=p2)></(?P=p1)>", html_str)
print(ret.group())
(?#...)
注释;括号的内容被忽略。
相当于没写。 就可以理解为 就是 写的注释
正则 断言匹配
断言的组成之一是边界。对于文本、词或模式,边界可以用来表明它们的起始或终止部分(如向前断言,向后断言以及条件表达式)。
(?=...)
=> 匹配 某字符跟随某某字符 ,匹配前者。
匹配如果 ...
匹配下一个
,但不使用任何字符串。这叫A lookahead assertion
前瞻性断言
或者说 先行断言
. 例如, Isaac (?=Asimov)
将匹配 'Isaac '
只有在后面跟着 'Asimov'
.
向前断言:例如,对于 Jack(?=Sprat)
,“Jack”
在跟有“Sprat”
的情况下才会得到匹配
./Jack(?=Sprat|Frost)
/ “Jack”
后跟有“Sprat”
或“Frost”
的情况下才会得到匹配
。不过, 匹配结果
不包括
“Sprat”或“Frost”。
所谓的先行
是指的匹配的东西先行
条件后行。
tips: 记忆小技巧 有箭头的断言
条件都写在 前面
的。
所以 都是后行。
先行断言 匹配的模式字符写在 前面
后行断言 匹配的模式字符串写在后面
断言就是指定条件。 不匹配字符。
In [81]: pat=r'Isaac (?=Asimov)'
In [82]: p=re.compile(pat)
In [85]: p.search("Isaac Asimovv") # 可以理解为 匹配 以某字符串结尾的 字符。
Out[85]: <_sre.SRE_Match object; span=(0, 6), match='Isaac '>
(?!...)
=> 匹配 某字符串 后面没跟着某某字符。匹配前者。
匹配如果 ...
与下一个不匹配
。这是一个 negative lookahead assertion
否定超前断言
向前否定断言
. 例如, Isaac (?!Asimov)
将匹配 'Isaac '
只要后面不是 'Asimov'
.
需要注意 ()里
这个是条件
是不会被匹配
到的
In [69]: pat=r'Isaac (?!Asimov)'
In [74]: p.search("Isaac Asimo")
Out[74]: <_sre.SRE_Match object; span=(0, 6), match='Isaac '>
In [76]: p.search("Isaac Asimov")# 不匹配
In [77]: p.search("Isaac Asimovv")# 不匹配
In [78]: p.search("Isaac aAsimovv") # 匹配
# 可以理解为 匹配 不以 某字符串 结尾的 字符
Out[78]: <_sre.SRE_Match object; span=(0, 6), match='Isaac '>
(?<=...)
=> 匹配前面是某某字符的某字符。匹配后者
如果字符串中的当前位置前面有匹配项
,则匹配
...
在当前位置结束
。这叫A positive lookbehind assertion
肯定断言
或者叫做 向后肯定断言
.
(?<=abc)def
将在中找到匹配项 'abcdef'
,因为lookback将备份3个字符并检查包含的模式是否匹配。
包含的模式必须只匹配某个固定长度的字符串,这意味着 abc
或 a|b
是允许的,但是 a* 和 a{{3,4}} 不是
请注意,以正的lookbehind断言开头的模式在被搜索的字符串的开头将不匹配;您很可能希望使用 search()
函数而不是 match()
功能:
需要注意 ()里
这个是条件
是不会被匹配
到的
import re
# 前面 有 abc 那么 我就 匹配 def
m = re.search('(?<=abc)def', 'abcdef')
# 可以理解为以某字符串开头的 字符
m.group(0)
# 输出
'def'
# 此示例查找连字符后的单词:
# 前面有连字符 那么我就匹配后面的 这个字符
m = re.search(r'(?<=-)\w+', 'spam-egg')
m.group(0)
'egg'
(?<!...)
=> 匹配 前面不是某某字符我就匹配某字符。 匹配后者
如果字符串中的当前位置前面没有匹配项,则匹配 … . 这叫A negative lookbehind assertion
向后否定断言
.
与正查找断言类似,包含的模式必须只匹配某些固定长度的字符串。
以负的lookbehind断言开头的模式可能在要搜索的字符串的开头匹配。
需要注意 ()里
这个是条件
是不会被匹配
到的
In [87]:
...: import re
# 前面 不是 adc 那么我就匹配后面的字符
...: m = re.search('(?<!abc)def', 'abcdef') # 未匹配到任何东西
In [90]:
...: import re
...: m = re.search('(?<!abc)def', 'bcdef') # 可以理解为不以某某开头的字符 后面的字符
In [91]: m.group()
Out[91]: 'def'
(?(id/name)yes-pattern|no-pattern)
如果给定的组 id 或 name
指向的组 有值
将尝试 使用 yes-pattern
匹配一些字符 ,否则尝试使用 no-pattern
匹配一些字符 。 no-pattern
是可选的,可以省略。
特殊序列包括 '\'
以及下面列表中的一个字符。如果普通字符不是一个ASCII
数字或一个ASCII
字母,那么得到的RE将与第二个字符匹配。例如, \$
与 '$'
匹配 .
相信 看完 这几张图 然后 自己实验 一下 所有人都能理解这是什么意思。
pat="(\w+@\w+(?:\.\w+)+)"
pat="(<)?(\w+@\w+(?:\.\w+)+)(?(1)>|>$)"
s1
的分组id
为1
的 匹配了<
说明有值 那么match=<user@host.com
使用yes
模式 尝试匹配>
因为s1
是user@host.com
所以匹配成功s3
的分组id
为1
的 组 值为None
所以使用no
模式 。然后s3=user@host.com>
所以no
模式我写的 匹配>
也匹配到了。
常用正则速查
/这里是正则/
js 中正则就是 写在 //
下划线中的
示例(比如我要验证用户名)
import re
pat='^[a-z0-9_-]{3,16}$'
str="你要验证的字符串"
re.match(pat,str)
如果已有的正则 不符合你的 要求
记得自己修改一下哦
用户名 | /^[a-z0-9_-]{3,16}$/ |
---|---|
密码 | /^[a-z0-9_-]{6,18}$/ |
十六进制值 | /^#?([a-f0-9]{6}|[a-f0-9]{3})$/ |
电子邮箱 | /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/ /^[a-z\d]+(\.[a-z\d]+)*@([\da-z](-[\da-z])?)+(\.{1,2}[a-z]+)+$/ |
URL | /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/ |
IP 地址 | /((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)/ /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ |
HTML 标签 | /^<([a-z]+)([^<]+)*(?:>(.*)<\/\1>|\s+\/>)$/ |
删除代码\\注释 | (?<!http:|\S)//.*$ |
Unicode编码中的汉字范围 | /^[\u2E80-\u9FFF]+$/ |