文章目录
辅助阅读:
- https://blog.csdn.net/hehe_win/article/details/54602584
- 基于《笨办法学习Python3》
- 修订:2
正则表达式
择一匹配 | 匹配的字符串 |
---|---|
bat|bet|bit | bat、bet、bit |
匹配 句点位置 | 匹配的字符串 |
---|---|
f.o .end | |
… | 任意 两字符 |
转义字符:‘\’
search():搜索——任何位置开始匹配
match():匹配——起始字符开始匹配
搜索 起始和结尾部分指定:"\A 或 ^"
匹配 字符串的末尾位置:"$ 或 \Z"
美元符号:
.*\$$
注意:书中目前没说\A和\Z用法
起始和结尾部分指定
起始和结尾部分指定 | 匹配的字符串 |
---|---|
^From /bin/tcsh$ | 起始字符…【行首】 …结尾字符 |
^Subject:hi$ | 单独字符串 |
单词边界:在匹配时会忽略换行和特殊字符
例如: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] |
正则表达式[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
“()”使自己相关的匹配被缓存,?:放在第一个选项前来抵消这种副作用
但这些匹配不会保存下来供后须使用和数据检索
(?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模块函数:常见的正则表达式属性》
参考:
为了更好的理解,只推进书中进度,上面反斜杠和单引有错
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正则表达式之 - ?: / ?= / ?!
>>> 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)
- (?x):空格必须用
[ ]
代替,否则执行结果不同- 参考地址:正则表达式中 ?=.* 是什么含义? - 知乎用户的回答 - 知乎
?p=<name>
返回布尔值
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()
参考地址:上面只是摘选
示例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/108769380from 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