【1.1正则表达式】Python核心编程(第三版)猴子都能看懂的笔记


辅助阅读:

  • https://blog.csdn.net/hehe_win/article/details/54602584
  • 基于《笨办法学习Python3》
  • 修订:2

在这里插入图片描述

正则表达式

择一匹配匹配的字符串
bat|bet|bitbat、bet、bit
匹配 句点位置匹配的字符串
f.o
.end
任意 两字符

转义字符:‘\’

search():搜索——任何位置开始匹配

match():匹配——起始字符开始匹配

搜索 起始和结尾部分指定:"\A 或 ^"

匹配 字符串的末尾位置:"$ 或 \Z"

美元符号:.*\$$

注意:书中目前没说\A和\Z用法

起始和结尾部分指定

起始和结尾部分指定匹配的字符串
^From
/bin/tcsh$
起始字符…【行首】
…结尾字符
^Subject:hi$单独字符串
img img

单词边界:在匹配时会忽略换行和特殊字符

例如:James 1abc,正则\Babc,结果找到

单词边界匹配

单词边界匹配匹配的字符串
the任何包含
\bthe起始字符**【单词边界】**
\bthe\b仅匹配单词**【会忽略特殊字符】**
\Bthe不以the开头

限定范围和否定

限定范围和否定
b[aeiu]t
[cr][23][dp][o2]
匹配方括号中包含的任何单字符**【字符集】**
Z.[0-9]
[A-Za-z][env-y]
小数**【指定字符范围】**
[^ASD]不匹配的 单字符
[^\t\n]不匹配的 制表符
["-a]ASCII系统,所有系统位于""和"a"之间,即34-97之间

正则表达式[ab],'a’和’b’是相互独立,但只能匹配单字符

否则用a|b

使用闭包操作符实现存在性和频数匹配。。。
[dn]ot?0~1次出现
0?[1-9]01~09月
[0-9]{15,16}匹配15~16次**【信用卡号码】**
</?[^>]+>匹配全部HTML标签**【不验证有效性】**
[KQRBNP][a-h][1-8][a-h][1-8]~~在“长代数”标记法中,表示国际象棋合法的棋盘移动(仅移动,不包括吃子和将军)。即K、Q、R、B、N、P等字母后加上a1h8之间棋盘坐标。坐标1从哪走,坐标2走到哪个位置~

\*匹配星号

多次使用问号:问号在任何使用闭合操作符的匹配后面,它将直接要求正则表达式引擎匹配尽可能少的次数+

正则常用符号

Name匹配前面正则
(*)0+ 【Kleene闭包】
(+)1+ 【正闭包操作符】
(?)0~1
[Mr?]:Mr或M
{M,N}
{M}
匹配 前面正则 M~N次
表示字符集的特殊字符
\d十进制数字
\D非十进制数
[^0-9]
\w全部字母数字
[A-Za-z0-9_]
\s空白字符
\w+-\d+				#字母数字-数字
'''减号只在字节集下有效'''
#a1-1
#2a-2

[A-Za-z]\w*			#首字符是任意字母大小写,其余是字母或数字,可有可无
\d{3}-\d{3}-\d{4}	#美国号码:800-555-1212
\w+@\w+\.com		#简单电子邮件地址

使用圆括号指定分组扩展表示法

可用闭包操作符 独立执行部分“()“

\d+(\.\d*)?							#浮点数,会保留句点
(Mr?s?\.)?[A-Z][a-z]*[A-Za-z-]+		#M.Co-co

在这里插入图片描述

【称谓可有可无】,【首字母大写】,【小写字母可有可无】,【字母、大小写或”-“】一次以上

扩展表示法

圆括号有一个副作用:匹配模式的子字符串可以保存起来供后续使用。这些子组能够被同一次的匹配或者搜索重复调用,或者提取出来用于后续处理。【后续会讲到group()…】

示例:1.3.9

“()”使自己相关的匹配被缓存,?:放在第一个选项前来抵消这种副作用

但这些匹配不会保存下来供后须使用和数据检索

参考:python re 扩展表示法

(?iLmsux)在正则表达式中嵌入一个或者多个特殊"标记"参数(?x),(?im)

(?:…)表示一个匹配不用保存的分组(?:\w+.)*

(?P<name>...)像一个仅由name标示而不是数字ID标示的正则分组匹配(?P<data>)

(?P=name)在同一个字符串中匹配由(?P<name)分组的之前文本(?P=data)

(?#…)标示注释,所有内容都被忽略(?#comment)

(?=…)匹配条件是如果…出现在之后的位置,而不适用输入字符串;称作正向前视断言(?=.com)

(?!..)匹配条件是如果…不出现在之后的位置,而不使用输入字符串;称作负向前视断言(?!.net)

(?<=…)匹配条件是如果…出现在之前的位置,而不使用输入字符串;称作正向后视断言(?<=800-)

(?<!..)匹配条件是如果…不出现在之前的位置,而不使用输入字符串;称作负向后视断言(?<!192.168.)

(?(id/name)Y|N)如果分组所提供的id或者name存在,就返回正则表达式的条件匹配Y,如果不存在,就返回N;|N是可选项。(?(1)y|X)

(?:\w+\.)*			#表示一个匹配不用保存的分组
(?#comment)			#注释
(?=.com)			#任意字符.com
(?!.net)			#字符不是跟着.net
(?<=800-)			#字符头部为“800-”才匹配
(?<!192\.168\.)		#字符之前不是192.168.才做匹配 【过滤C类IP地址】
(?(l)y|x)			#

最后一个没搜到什么作用

1.3正则表达式和Python语言

常见的正则表达式属性

函数/方法描述
仅仅是re模块函数
compile(pattern,flags=0)使用任何可选的标记来编译正则表达式的模式,然后返回一个正则表达式对象
re 模块的函数和正则表达式对象的方法
match(pattern,string, flags=0)尝试使用带有可选的标记的正则表达式的模式来匹配字符串。如果匹配成功,就返回匹配对象;如果失败,就返回None
search(pattern,string, flags=0)尝试可选标记搜索字符串中第一次出现的正则表达式模式。如果匹配成功,就返回匹配对象;如果失败,就返回None
findall(pattern,string[,flags])查看字符串中所有(非重复)出现的正则表达式模式,并返回一个匹配列表
finditer(pattern,string[, flags])与findall()函数相同,但返回的不是一个列表,而是一个迭代器。对于每一次匹配,迭代器都返回一个匹配对象
split(pattern,string, max=0)根据正则表达式的模式分隔符,split函数将字符串分割为列表,然后返回成功匹配的列表,分割最多操作max次(默认分割所有匹配成功的位置)
sub(pattern, repl, string, max=0)使用repl替换所有正则表达式的模式在字符串中出现的位置,除非定义count,否则就将替换所有出现的位置
purge()消除隐式编译的正则表达式模式
常见的匹配方法
group(num=0)返回整个匹配对象,或者编号为num的特定子组
groups(default=None)返回一个包含所有匹配子组的元组(如果没有成功匹配,则返回一个空元组)
groupdict(default=None)返回一个包含所有匹配的命名子组的字典,所有的子组名称作为字典的键(如果没有成功匹配,则返回一个空字典)
常用的模块属性
re.I、re.IGNORECASE不区分大小写的匹配
re.L、re.LOCALE根据所使用的本地语言环境通过\w、\W、\b、\B、\s、\S实现匹配
re.M、re.MULTILINE^和$分别匹配目标字符串中行的起始和结尾,而不是严格匹配整个字符串本身的起始和结尾
re.S、re.DOTALL“.”(点号)通常匹配除了\n(换行符)之外的所有单个字符;该标记表示“.”(点号)能够匹配全部字符
re.X、re.VERBOSE通过反斜线转义,否则所有空格加上#都被忽略,除非在一个字符类中或者允许注释并且提高可读性

compile()

1.1章节并没有相关示例,后期补充

1.3.4使用match()方法匹配字符串

match()函数从起始位置匹配,匹配成功:返回对象,否则None

m = re.match('(ab)', 'ab')
m.group(1)           # 子组 1

group()返回值:整个匹配对象、‘特定要求子组。

groups()返回值:包含1个以上子组的元组。

若无子组group()返回完整匹配,groups() 返回空元组“()”

re.match('ab', 'ab').group()		# 没有子组
'ab'								# 完整匹配
m.groups()           				# 所有子组
()
import re

bt = 'bat|bet|bit'
re.match(bt,'batL').group()						#'bat'
re.search(bt, 'He bit me!') .group()			#'bit'
# 起始位置【匹配】
# 任意位置【搜索】
# 判断避免AttributeError异常,group()无法处理None



m = re.search('.end', 'The end.')
if m is not None:print(m.group())		# “ end”
#if m !=None:print(m.group()
    
re.match('3\.14', '3.14').group()		# 3.14
'''
(.)句点叫空字符可以替换小数点,不能匹配 换行符 或者 非字符 ,不包括空格
'''

"模式"叫“pattern”——匹配的正则表达式,书中叫法特

择一匹配的范围更局限

re.match('[cr][23][dp][o2]', 'c2do')
re.match('r2d2|c3po', 'c2do')		# 不匹配 'c2do'

1.3.9 重复、特殊字符以及分组

re.match('(ab)', 'ab').groups()		# ('ab',)


m = re.match('(a)(b)', 'ab')
m.group()							# 'ab' ——整个匹配对象
m.group(2)							# b
m.groups()							# ('a', 'b')


m = re.match('(a(b))', 'ab')		
m.groups()							# ('ab', 'b')

group() 返回整个匹配对象、要求的特定子组。

groups() 返回包含全部或唯一子组的元组、无匹配返回空元组

import re
单次子域名 = '\w+@(\w\.)?\w\.com'
多次子域名 = '\w+@(\w+\.)*\w+\.com'
特殊地址 = '(\w+)-(\d+)'
#nobody@www.xxx.com
#nobody@xxx.com
#nobody@www.xxx.yyy.zzz.com

1.3.10 匹配字符串的起始和结尾以及单词边界

search()和match()用法完全一致,当前进度group()都没数据

re.search('^The', 'The end.').group()		#'The'

m = re.search('^The', 'end.The')			# 不作为起始
if m is not None: m.group()
...
#任何以The为起始的字符串
re.search('^The', 'The end.').group()
#同match()从起始位置进行匹配
#re.search('^The', 'end.The').group()	#None	

# 起始字符【单词边界】
re.search(r'\bthe', 'bite the dog').group()		#the

# 包含 但不以the起始
re.search(r'\Bthe', 'bitethe dog').group()		#bitethe

不懂什么是有边界和无边界,但能理解命令,见:《起始和结尾部分指定》

1.3.11 使用findall()和finditer()查找每一次出现的位置

re模块函数:常见的正则表达式属性

函数/方法描述
仅仅是re模块函数
compile(pattern,flags=0)使用任何可选的标记来编译正则表达式的模式,然后返回一个正则表达式对象
re 模块的函数和正则表达式对象的方法
match(pattern,string, flags=0)尝试使用带有可选的标记的正则表达式的模式来匹配字符串。如果匹配成功,就返回匹配对象;如果失败,就返回None
search(pattern,string, flags=0)尝试可选标记搜索字符串中第一次出现的正则表达式模式。如果匹配成功,就返回匹配对象;如果失败,就返回None
findall(pattern,string[,flags])查看字符串中所有(非重复)出现的正则表达式模式,并返回一个匹配列表
finditer(pattern,string[, flags])与findall()函数相同,但返回的不是一个列表,而是一个迭代器。对于每一次匹配,迭代器都返回一个匹配对象
split(pattern,string, max=0)根据正则表达式的模式分隔符,split函数将字符串分割为列表,然后返回成功匹配的列表,分割最多操作max次(默认分割所有匹配成功的位置)
sub(pattern, repl, string, max=0)使用repl替换所有正则表达式的模式在字符串中出现的位置,除非定义count,否则就将替换所有出现的位置
purge()消除隐式编译的正则表达式模式
常见的匹配方法
group(num=0)返回整个匹配对象,或者编号为num的特定子组
groups(default=None)返回一个包含所有匹配子组的元组(如果没有成功匹配,则返回一个空元组)
groupdict(default=None)返回一个包含所有匹配的命名子组的字典,所有的子组名称作为字典的键(如果没有成功匹配,则返回一个空字典)
常用的模块属性
re.I、re.IGNORECASE使匹配对大小写不敏感(大写i)
re.L、re.LOCALE根据所使用的本地语言环境通过\w、\W、\b、\B、\s、\S实现匹配
re.M、re.MULTILINE==【多行匹配】==影响 ^ 和 < b r / > 和 <br />^和 <br/>分别匹配目标字符串中行的起始和结尾,而不是严格匹配整个字符串本身的起始和结尾
re.S、re.DOTALL==【单行模式】==使 “.”(点号)匹配包括换行在内的所有字符
re.X、re.VERBOSE通过反斜线转义,否则所有空格加上#都被忽略,除非在一个字符类中或者允许注释并且提高可读性

注意: match 和 search 是匹配一次 findall 匹配所有。

帮助地址:Finadall和Finditer区别

findall(string[, pos[, endpos]])

  • string 待匹配的字符串。
  • pos 可选参数,指定字符串的起始位置,默认为 0。
  • endpos 可选参数,指定字符串的结束位置,默认为字符串的长度。

findall(pattern,string[,flags]) 【匹配列表】查看字符串中所有(非重复)出现的正则表达式模式,并返回一个匹配列表

重复:r'(th\w+) and (th\w+)' 是指这里有两个一样的表达式

[‘car’, ‘car’, ‘car’]

finditer(pattern,string[, flags]) 【迭代器】与findall()函数相同,但返回的不是一个列表,而是一个迭代器。对于每一次匹配,迭代器都返回一个匹配对象

[(‘This’, ‘that’)] #要求多个字组

>>> re.findall('car', 'carry the barcardi to the car')
['car', 'car', 'car']

re模块的*finditer()函数报出AttributeError*: ‘callable_iterator’ object has no attribute ‘next’*的错误:

https://blog.csdn.net/weixin_43148062/article/details/105639146+

>>> s = 'This and that.'



#当前版本【3.9】
>>> it = re.finditer(r'(th\w+) and (th\w+)',s,re.I)
>>> next(it).groups()
('This', 'that')

#书中写法【过时】
>>> it.next().groups()
出错了

别管为啥有个逗号,他只有一个元素,也不要next(it)两次,除非重新赋值变量,会出错的

\w会在空字符作为边界

re.I(不区分大小写)

import re
s = 'This and that.'
res = re.finditer(r'(th\w+) and (th\w+)',s,re.I)
print(next(res).group(2))
#print(next(res).groups())
#只能执行一行

============================================
that
============================================
('This', 'that')

next()不仅会返回下一行,猜测是同概念,但指向不同东西,不明白为啥加next()

#下面是字节码,0是起始位置
>>> print(next(it))
<re.Match object; span=(0, 4), match='This'>
import re
s = 'This and that.'


'''多个子组'''
re.findall(r'(th\w+) and (th\w+)', s, re.I)		#[('This', 'that')]
re.findall(r'(th\w+)', s, re.I)					#['This', 'that']
import re
s = 'This and that.'							#r原样输出

res = re.finditer(r'(th\w+) and (th\w+)',s,re.I)
g = next(res)
g.groups()								#('This', 'that')
#全部子组

res = re.finditer(r'(th\w+) and (th\w+)',s,re.I)
g = next(res)
g.group(2)								#'that'
#子组2

[g.group(1) for g in re.finditer(r'(th\w+)', s, re.I)]
#['This', 'that']
import re
s = 'This and that.'


res = re.finditer(r'(th\w+) and (th\w+)',s,re.I)
g = next(res)

m = re.finditer(r'(th\w+)', s, re.I)
print(next(m).groups())
print(next(m).groups())

#for gg in re.finditer(r'(th\w+)', s, re.I):
#    print(gg.group(1))
#z = [g.group(1) for gg in re.finditer(r'(th\w+)', s, re.I)]
#print(z)
==================================
('This',)
('that',)

[g.group(1) for g in re.finditer(r'(th\w+)', s, re.I)],我拆开理解了, 每次next()都会返回一个新元组内元素,

import re
s = 'This and that.'

z = [g.group(1) for g in re.finditer(r'(th\w+)', s, re.I)]                      #['This', 'that']
print(z)

re.finditer(r'(th\w+)', s, re.I)返回列表,for每次循环的列表成员(这里是元组元素)从索引0开始,每次循环会赋值给内部临时变量g ,循环次数有列表成员数长度决定,每次循环会让变量更新一次,for有更高优先性,随后group(1)就会输出一个数据,循环2次就两个数据。【列表内是可以执行函数的】

使用sub()和subn()搜索与替换

  • re.sub(‘查找’, ‘替换为’, ‘字符串’) 实现搜索与替换功能,返回替换后的字符串。

  • subn(‘查找’, ‘替换为’, ‘字符串’) 实现搜索与替换功能,返回元组:替换后字符、替换总数

>>> import re
>>> 
>>> re.sub('查找、正则', '替换为', '字符串')
'处理结果'
>>> re.subn('查找', '替换为', '字符串')
('处理结果', 总数)

>>>
re.sub('[ae]', '+', 'abcdef')
'+bcd+f'
>>> re.subn('[ae]', '+', 'abcdef')
('+bcd+f', 2)

>>> print (re.sub('X', 'Mr.Smith', 'attn: X\nDear X,\n'))
attn: Mr.Smith
Dear Mr.Smith,


#匹配两次1或2位数字,匹配2或4位数字
>>> re.sub(r'(\d{1,2})/(\d{1,2})/(\d{2}|\d{4})',r'\2/\1/\3','2/20/91')
'20/2/91'
>>> re.sub(r'同上','同上','2/20/1991')
'20/2/1991'

发现一个意料之外:无关不帮助理解【参考:贪婪匹配】

>>> re.sub(r'(\d{1,2})/(\d{1,2})/(\d{2}|\d{4})',r'\2/\1/\3','33777777777744/20/1991')
'33777777777720/44/1991'

在限定模式上使用split()分隔字符串

文本.split(str="", num=string.count(str)).

split(pattern,string, max=0)

根据split分割文本,返回成功匹配列表,分割最多操作max次。(默认无上限)

split可以代替复杂且影响性能的正则表达式。

for 临时 in 元组:
print(re.split(‘表达式’,临时))

>>> import re
>>> DATA=(
     'Mountain View,VA94040',
     'Sunnyvale, VA',
     'Los Altos, 94023',
     'Cupertino 95014',
     'Palo Alto CA',
 )
>>> for datum in DATA:
     print (re.split(', |(?= (?:\d{5}|[A-Z]{2})) ',datum))

'''任意字符(不保存分组,数字5位或 任意两个大写字母)'''
""" 
'逗号'在print打印时就没有了,因为在字符串外,所以for基于逗号进行了逐个取出
正则中逗号代表
"""
        
        
        
#(?:...)没找到会变成None,加上这个不会输出None在里面
#例如:?=.com,任意字符.com
=========================================
['Mountain View', 'VA', '94040']
['Sunnyvale', 'VA']
['Los Altos', '94023']
['Cupertino', '95014']
['Palo Alto', 'CA']

在这里插入图片描述

上图:不加?:,下图反之

在这里插入图片描述

扩展符号

re.M/re.MULTILINE实现多行混合

常用命令见:《re模块函数:常见的正则表达式属性》

参考:

【推荐】Python正则表达式中的re.S,re.M,re.I的作用

re.S 和 re.M的一点区别

在这里插入图片描述

为了更好的理解,只推进书中进度,上面反斜杠和单引有错

  • re.m(?m):跨行搜索,不必将整个字符串视为单个实体

  • re.i(?i):不区分大小写

#不区分大小写
>>> re.findall(r'(?i)yes','yes? yesYes. YES!!')
['yes', 'yes', 'Yes', 'YES']



import re


#部分大小写,多行匹配
s =re.findall(r'(?im)(^th[\w ]+)', """
This line is the first,
another line,
that line,
it's the best
""")

print(s)

================================================


['This line is the first', 'that line']

re.S/re.DOTALL使点号能够用来表示\n符号

res.s:==【单行模式】==使 “.”(点号)匹配包括换行在内的所有字符

>>> re.findall(r'th.+','''
The first line
the second line
the third line
''')
['the second line', 'the third line']

>>> re.findall(r'(?s)th.+', '''
The first line
the second line
the third line
''')
['the second line\nthe third line\n']

re.X/VERBOSE

换一种说法解释:这个选项忽略规则表达式中的空白和注释,并允许使用 ’#’ 来引导一个注释。这样可以让你把规则写得更美观些。

(书里写的真是拐弯抹角)

re.search(r'''(?x)
     \((\d{3})\)  #区号
     [ ]          #空白符
     (\d{3})      #前缀
     -            #横线
     (\d{4})      #终点数字
 ''','(800) 555-1212').groups()

#如果还在懵圈请把正则和被匹配的空格去掉,这会干扰理解
#另外我常省略导入re

(?:…)对正则表达式进行分组

使用圆括号会被缓存,使用(?:…)不会缓存,只用来匹配正确性

帮助:【推荐】Python正则表达式之 - ?: / ?= / ?!

Python 正则表达式(分组)

正则表达式(四):正则表达式中的分组的概念

>>> re.findall(r'http://(?:\w+\.)*(\w+\.com)','http://google.com http://www.google.com http://code.google.com')
['google.com', 'google.com', 'google.com']

不加?:

split()中用正则会保留可见的None文本,findall()不会

>>> re.findall(r'http://(\w+\.)*(\w+\.com)','http://google.com http://www.google.com http://code.google.com http://www.code.aaa.google.com')

==================================================
[('', 'google.com'), ('www.', 'google.com'), ('code.', 'google.com'), ('aaa.', 'google.com')]

在线工具中与实际输出不同:https://tool.oschina.net/regex#

在这里插入图片描述

(?P< name >)

返回:根据?p<name>的name为字典键名

>>> re.search(r'\((?P<areacode>\d{3})\) (?P<prefix>\d{3})-(?:\d{4})','(800) 555-1212').groupdict()
{'areacode': '800', 'prefix': '555'}

\g<name>

参考:re模块中 (?P<name>) (?P=name)\g<name> 三者的使用区别

可以使用(?P<name>)创建元组,然后用(\g<name>)复用这个匹配

import re

astr = 'aabb aacc aadd'
result = re.sub(r'(?i)aa(?P<pattern>[\w]+)',r'bb\g<pattern>',astr)
print('{} _____ {}'.format(astr,result))

re.sub(r'\((?P<areacode>\d{3})\) (?P<prefix>\d{3})-(?:\d{4})','(\g<areacode>) \g<prefix>-xxxx', '(800) 555-1212')

#上面书里没有的命令一看就会吧
=================================
aabb aacc aadd _____ bbbb bbcc bbdd

(?x)

import re

s = bool(re.match(r'''(?x)\((?P<areacode>\d{3})\) (?P<prefix>\d{3})-(?P<number>\d{4}) (?P=areacode)-(?P=prefix)-(?P=number) 1(?P=areacode)(?P=prefix)(?P=number)''','(800) 555-1212 800-555-1212 18005551212'))


z = bool(re.match(r'''(?x)
    \((?P<areacode>\d{3})\)[ ](?P<prefix>\d{3})-(?P<number>\d{4})
     [ ]
     (?P=areacode)-(?P=prefix)-(?P=number)
     [ ]
      1(?P=areacode)(?P=prefix)(?P=number)
 ''', '(800) 555-1212 800-555-1212 18005551212'))

print(s)

print('\n',z)
===================================================
False

 True

字符串格式化符号

在这里插入图片描述

  • 参考地址:https://jingyan.baidu.com/article/454316abaf775ab6a6c03a7b.html
>>> '%c 打印一个字母'  % (97)
'a 打印一个字母'
>>> '单推%s 娘'  % '22'
'22 娘'

正向前视断言(?…) 负向前视断言 (?!…)

  • 参考:https://blog.csdn.net/csm0912/article/details/81206848

    https://zhidao.baidu.com/question/1110915947964324019.html

  • 断言正则成立,则运行子组正则

// 正向前视断言	【要求之内】
exp1(?=exp2) 	//exp2前面是exp1
(?<=exp2)exp1 	//exp2后面是exp1


// 负向前视断言	【要求之外】
exp1(?!exp2) 	//exp1后面不是exp2
(?<!exp2)exp1 	//exp1前面不是exp2
re.findall(r'\w+(?= van Rossum)',
'''
   Guido van Rossum
   Tim Peters
   Alex Martelli
   Just van Rossum
   Raymond Hettinger
''')

==============================================
['Guido', 'Just']
  • ?m【多行匹配】不需要像?x那样使用[ ]来充当空格,而是原始文本输出

  • \s用于匹配空白字符。所以正则:以空白字符开头的字符

  • 字符边界(重复):一 二 三 ,就跟编辑器Ctrl+D一样

    在这里插入图片描述

import re

#?m【多行匹配】
#\s【空字符】
z = re.findall(r'(?m)^\s+(?!noreply|postmaster)(\w+)',
'''
   sales@phptr.com
   postmaster@phptr.com
   eng@phptr.com
   noreply@phptr.com
   admin@phptr.com
''')


print('\n',z)


============================================
['sales', 'eng', 'admin']
  • 请参考《字符串格式化符号》,这就类似于f'{}{}'.format('1','2') 输出:‘12’
import re

z = ['%s@aw.com' % e.group(1) for e in \
re.finditer(r'(?m)^\s+(?!noreply|postmaster)(\w+)',
'''
   sales@phptr.com
   postmaster@phptr.com
   eng@phptr.com
   noreply@phptr.com
   admin@phptr.com
''')]

print('\n',z)
=================================================
 ['sales@aw.com', 'eng@aw.com', 'admin@aw.com']

使用条件正则表达式匹配

  • ?(1)参考链接,我看不太懂,貌似和布尔值有关

bool()类型判断::https://blog.csdn.net/u014472777/article/details/90318960

print(bool(re.search(r'(?:(x)|y)(?(1)y|x)','xy')))		#True
print(bool(re.search(r'(?:(x)|y)(?(1)y|x)','yx')))		#True
print(bool(re.search(r'(?:(x)|y)(?(1)y|x)','x')))		#False
#使用条件正则表达式。上述匹配一个字符串:两个字母必须由一个字母跟着另一个字母,两个字母不能相同

退格符\b和正则表达式\b之间的差异

\w和\W字母数字字符集同时受re.L/LOCALEUnicode(re.U/UNICODE)标记所影响。

书里很多是啰嗦。

  • '\b' = 退格符
  • '\\b' = \b
  • r'\b' = 单词边界

\d 使用原始字符串时并未遇到问题,这是因为ASCII中没有相应的特殊字符

>>> m=re.match('\bblow','blow')
>>> if m:    m.group()
...
>>> m=re.match('\\bblow','blow')
>>> if m:    m.group()
...
'blow'
>>> m=re.match(r'\bblow','blow')
>>> if m:    m.group()
...
'blow'

一些正则表达式示例

  • 为啥实例化文本才会按行读取,直接赋值多行不可以
  • r'字符串' 用于避免转义特殊字符串字符,如\n,可以用\\s 代表\s
System Idle Process              0 Services                   0          4 K
System                           4 Services                   0      9,212 K
smss.exe                       464 Services                   0        544 K
csrss.exe                      708 Services                   0      2,792 K
wininit.exe                    816 Services                   0      2,808 K
services.exe                   888 Services                   0      5,220 K
lsass.exe                      904 Services                   0     10,984 K
re.split(r'正则匹配分隔文本', 字符串)
import re

for i in open('whodata.txt', 'r'):
    print(re.split(r'\s\s+',i))
#个人写法↑
===================================================
['System Idle Process', '0 Services', '0', '4 K\n']
['System', '4 Services', '0', '9,212 K\n']
['smss.exe', '464 Services', '0', '544 K\n']
['csrss.exe', '708 Services', '0', '2,792 K\n']
['wininit.exe', '816 Services', '0', '2,808 K\n']
['services.exe', '888 Services', '0', '5,220 K\n']
['lsass.exe', '904 Services', '0', '10,984 K\n']

示例1-1 分割windows的tasklist命令 file对象

  • 去除尾部的\n(使用 str.rstrip())

Python2**(Python3见示例1-3)**

使用str.rstrip()去除尾部的\n

import os
import re
f = os.popen('tasklist', 'r')
for eachLine in f:
    print re.split(r'\s\s+|\t', eachLine.rstrip()) #使用str.rstrip()去除尾部的\n
f.close()


=======================================================
部分python结果展示:
['\xd3\xb3\xcf\xf1\xc3\xfb\xb3\xc6', 'PID \xbb\xe1\xbb\xb0\xc3\xfb', '\xbb\xe1\xbb\xb0#', '\xc4\xda\xb4\xe6\xca\xb9\xd3\xc3']
['========================= ======== ================ =========== ============']
['System Idle Process', '0 Services', '0', '4 K']
['System', '4 Services', '0', '9,212 K']
['smss.exe', '464 Services', '0', '544 K']
['csrss.exe', '708 Services', '0', '2,796 K']
['wininit.exe', '816 Services', '0', '2,808 K']
['services.exe', '888 Services', '0', '5,220 K']
['lsass.exe', '904 Services', '0', '10,968 K']

示例1-2 分割windows的tasklist命令 with语句

  • Python3.9多行超长输出:他是程序内部运行的Shell命令,简单理解是遍历目录

with语句兼容性(最低支持2.6)

  • 2.5为试验性的,2.5需要导入额外的语句

    from __future__ import with_statement。
    
  • 2.4或更低:

    只能用示例1-1了

from distutils.log import warn as printf是一个兼容2和3的括号:参考

调用其他程序,需要调用os.popen()

tasklist 是个cmd命令,返回一个文件列表

import os
import re
with os.popen('tasklist', 'r') as f:
    for eachLine in f:
        print re.split(r'\s\s+|\t', eachLine.rstrip())
file = open("/tmp/foo.txt")
try:
    data = file.read()
finally:
    file.close()

try是判断一个命令是否报错,然后不管是否出错都会执行finally

with可以简化:打开文件参数,路径一般都是相对路径。as命令参数赋值file

with open("/tmp/foo.txt") as file:
data = file.read()

参考地址:上面只是摘选

python中finally的作用

python中 with-as 语句用法

示例1-3 分割windows的tasklist命令 printf语句(2、3通用)

import os
from distutils.log import warn as printf
import re

with os.popen('tasklist', 'r') as f:
    for eachLine in f:
        printf(re.split(r'\s\s+|\t', eachLine.rstrip()))
部分python结果展示:
['\xd3\xb3\xcf\xf1\xc3\xfb\xb3\xc6', 'PID \xbb\xe1\xbb\xb0\xc3\xfb', '\xbb\xe1\xbb\xb0#', '\xc4\xda\xb4\xe6\xca\xb9\xd3\xc3']
['========================= ======== ================ =========== ============']
['System Idle Process', '0 Services', '0', '4 K']
['System', '4 Services', '0', '9,212 K']
['smss.exe', '464 Services', '0', '544 K']
['csrss.exe', '708 Services', '0', '2,796 K']
['wininit.exe', '816 Services', '0', '2,808 K']
['services.exe', '888 Services', '0', '5,220 K']
['lsass.exe', '904 Services', '0', '10,968 K']

示例1-4 处理DOS环境下tasklist命令的输出

import os
import re
f = os.popen('tasklist /nh', 'r')
for eachLine in f:
    print re.findall(r'([\w.]+(?: [\w.]+)*)\s\s+(\d+) \w+\s\s+\d+\s\s+([\d,]+ K)', eachLine.rstrip())
f.close()

Python3.9:

在这里插入图片描述

cmd:tasklist /nh

在这里插入图片描述

更长的正则表达式示例

示例1-5 用于正则表达式练习的数据生成器

该脚本为正则表达式练习创建随机数据,然后将生成的数据输出到屏幕。

参考
https://www.runoob.com/python/func-number-randrange.html
https://blog.csdn.net/qq_37369726/article/details/108769380

from random import randrange, choice

random.randrange (1,3 ) :要求范围内随机数,取随机数(小~大),最大值必填
random.choice(list):随机取列表成员

from string import ascii_lowercase as lc

所有的小写字母

'abcdefghijklmnopqrstuvwxyz'

from sys import maxint

返回系统最大整数。

from time import ctime

时间戳,返回一段自1970.1.1 8:00开始的秒数(格林威治午夜)

Sun Sep 7 17:29:09 2008

下面是随机的时间戳,肯定输出不一样

from random import randrange, choice
from sys import maxsize
from time import ctime
print(ctime(randrange(maxsize)))
=====================================
Mon Apr  8 02:54:12 2013

增量:

for temp in xrange(0,6):

快速创建有1~5整数列表,能限制for循环次数

序列也叫列表,填充后输出文本,列表被要求符号填充连接起来

在这里插入图片描述

  • 适配Python3
    • 修改Python,
    • xrange()修改为range(),
    • 将sys.maxint修改为sys.maxsize。
#Python2

from random import randrange, choice
from string import ascii_lowercase as lc # 全部小写字母集成	`为列表
from sys import maxint
from time import ctime

tlds = ('com', 'edu', 'net', 'org', 'gov')  # 高级域名集合

for i in xrange(randrange(5, 11)):
    dtint = randrange(maxint)  # 随机生成一个整数
    dtstr = ctime(dtint)       # 使用time.ctime()函数将该整数转换为日期
    llen = randrange(4, 8)     # login is shorter
    login = ''.join(choice(lc) for j in range(llen)) # random.choice()函数的功能是接受一个序列,然后返回该序列的一个随机元素
    dlen = randrange(llen, 13)  # domain is longer
    dom = ''.join(choice(lc) for j in xrange(dlen))
    print '%s::%s@%s.%s::%d-%d-%d' % (dtstr, login, dom, choice(tlds), dtint, llen, dlen)
#Python3

from random import randrange, choice
from string import ascii_lowercase as lc # 全部小写字母集成	`为列表
from sys import maxsize
from time import ctime

tlds = ('com', 'edu', 'net', 'org', 'gov')  # 高级域名集合

for i in range(randrange(5, 11)):
    dtint = randrange(maxsize)  # 随机生成一个整数
    dtstr = ctime(dtint)       # 使用time.ctime()函数将该整数转换为日期
    llen = randrange(4, 8)     # login is shorter
    login = ''.join(choice(lc) for j in range(llen)) # random.choice()函数的功能是接受一个序列,然后返回该序列的一个随机元素
    dlen = randrange(llen, 13)  # domain is longer
    dom = ''.join(choice(lc) for j in range(dlen))
    print ('%s::%s@%s.%s::%d-%d-%d' % (dtstr, login, dom, choice(tlds), dtint, llen, dlen))

输出结果:

在这里插入图片描述

匹配字符串

#正则表达式的简化
"^Mon|^Tue|^Wed|^Thu|^Fri|^Sat|^Sun"
"^(Mon|Tue|Wed|Thu|Fri|Sat|Sun)"
=========================================================


import re
data = 'Wed Mar 20 13:40:35 2002::geom@mnfdlm.edu::1016602835-4-6'


patt='^(Mon|Tue|Wed|Thu|Fri|Sat|Sun)'
m = re.match(patt,data)

print(
m.group(),
m.group(1),
m.groups()
)
=====================================
Wed Wed ('Wed',)

分组 ^()

当地的日期和缩写,可以是^\w{3}

import re
data='Wed Mar 20 13:40:35 2002::geom@mnfdlm.edu::1016602835-4-6'

patt = '^(\w{3})'
m = re.match(patt, data)
if m is not None: print(m.group())
print(m.group(1))


================================
Wed
Wed

当{3}在圆括号中时,先匹配三个连续的字母数字字符,然后表示为一个分组。但是如果将{3}移到外部,它就等效于三个连续的单个字母数字字符。

group(1)访问子组1时,子组1被持续被下一个字符替换。

换句话说:这些是单个字母数字字符的三个独立(并且重叠)分组,与一个包含三个连续字母数字字符的单独分组相反。

import re
data='Thu Feb 15 17:46:04 2007::uzifzf@dpyivihw.gov::1171590364-6-8'

patt = '^(\w){3}'
m = re.match(patt, data)
if m is not None:
    print('完整匹配', m.group())
    print('子组1:', m.group(1))


===============================================
Thu
u

搜索、匹配与贪婪

+是个贪婪匹配符号

import re
data='Thu Feb 15 17:46:04 2007::uzifzf@dpyivihw.gov::1171590364-6-8'

patt = '\d+-\d+-\d+'
m = re.search(patt, data)
if m is not None: print(m.group())
    
==========================================
1171590364-6-8

若用match()匹配则返回None。

re.match('.+(\d+-\d+-\d+)',data).group(1) 正则表达式从左至右扫描求值,并且试图获取尽可能多的字符串

在这里插入图片描述

import re
data='Thu Feb 15 17:46:04 2007::uzifzf@dpyivihw.gov::1171590364-6-8'

m = re.match('.+\d+-\d+-\d+',data).group()
j = re.match('.+(\d+-\d+-\d+)',data).group(1)

print(m,'\n'*2,j)
============================================
Thu Feb 15 17:46:04 2007::uzifzf@dpyivihw.gov::1171590364-6-8 
 4-6-8

书中错误:strip('::') 为删除首尾要求符号,直到首尾符号要求不存在为止。详见菜鸟教程

import re
data='Thu Feb 15 17:46:04 2007::uzifzf@dpyivihw.gov::1171590364-6-8'

S1 = re.split('::',data)
S2 = S1[2]              					#1171590364-6-8
#S3_zhi = re.match('\d+-\d+-\d+',S2).group()

print(S2)

==================================
1171590364-6-8
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值