正则学习
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了正则学习相关的知识,希望对你有一定的参考价值。
Re模块的方法
re.match函数
match尝试从字符串的起始位置开始匹配,如果不是起始位置匹配成功的话 返回None,匹配成功的话返回一个正则匹配对象;该方法与pattern.match()方法区别在于,它不能指定匹配的区间pos和endpos两个参数。只有pattern模式才可以指定配置的开始、结束位置;
语法:
re.match(pattern,string,flags=0)
pattern 匹配的正则表达式
String 要匹配的字符串
Flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等
起始位置匹配成功
>>> re.match(r"gloryroad","gloryroad")
<_sre.SRE_Match object; span=(0, 9), match=‘gloryroad‘>
>>> re.match(r"gloryroad","gloryroad").group()
‘gloryroad‘
起始位置匹配失败
>>> re.match(r"gloryroad","123gloryroad")
re.search函数
在整个字符串中进行扫描,并返回第一个成功的匹配,匹配成功返回一个正则匹配对象,匹配失败返回None;该方法与pattern.search()方法区别在于,它不能指定匹配的区间pos和endpos两个参数
语法:
re.search(pattern,string,flags=0)
pattern 匹配的正则表达式
String 要匹配的字符串
Flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等
成功匹配:
>>> re.search(r"[a-z]+\d+\s+","~abc123 \n~")
<_sre.SRE_Match object; span=(1, 9), match=‘abc123 \n‘>
>>> re.search(r"[a-z]+\d+\s+","~abc123 \n~").group()
‘abc123 \n‘
>>> re.search(r"(?P<g1>[a-z])\1\1","abc")
>>> re.search(r"(?P<g1>[a-z])\1\1","aaa")
<_sre.SRE_Match object; span=(0, 3), match=‘aaa‘>
>>> re.search(r"(?P<g1>[a-z])\1\1","aaa").group()
‘aaa‘
匹配失败:
>>> re.search(r"[a-z]+\d+\s+","~abc 123 \n~").group()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: ‘NoneType‘ object has no attribute ‘group‘
re.findall函数
获取字符串中所有能匹配的字符串,并以列表的形式返回。
语法:
re.findall(pattern,string,flags)
pattern:匹配的正则表达式
string:被匹配的字符串
flags:标志位,用于控制正则表达式的匹配方式。如是否区分大小写、是否多行匹配等
同样有不带分组,一个分组,多个分组的情况,参照pattern.fiindall()
不带分组
>>> re.findall(r"\d+[a-z]","1a2b3c4d")
[‘1a‘, ‘2b‘, ‘3c‘, ‘4d‘]
>>> import re
>>> re.findall(r"\d{2}","a123 a5678")
[‘12‘, ‘56‘, ‘78‘]
一个分组
>>> re.findall(r"(\d+)[a-z]","1a2b3c4d")
[‘1‘, ‘2‘, ‘3‘, ‘4‘]
多个分组
>>> re.findall(r"(\d+)([a-z])","1a2b3c4d") #两个分组
[(‘1‘, ‘a‘), (‘2‘, ‘b‘), (‘3‘, ‘c‘), (‘4‘, ‘d‘)]
>>> re.findall(r"((\d+)([a-z]))","1a2b3c4d")#3个分组
[(‘1a‘, ‘1‘, ‘a‘), (‘2b‘, ‘2‘, ‘b‘), (‘3c‘, ‘3‘, ‘c‘), (‘4d‘, ‘4‘, ‘d‘)]
re.finditer函数
匹配字符串中所有满足条件的子串,返回一个迭代器,迭代器里面的存储的是每一个匹配结果的匹配对象,这样可以节省空间
re.finditer(patern,string,flags)
pattern:匹配的正则表达式
string:被匹配的字符串
flags:标志位,用于控制正则表达式的匹配方式。如是否区分大小写、是否多行匹配等
>>> for m in re.finditer(r"\[email protected]\w+\.\w{2,3}","[email protected] [email protected]"):
... print(m.group())
...
[email protected]
[email protected]
re.split函数
把需要匹配的字符串按照正则表达式匹配的结果为分割符进行分割,并返回分割后的列表
语法:
re.split(pattern,string,maxsplit,flags)
pattern:匹配的正则表达式
string:被分割的字符串
maxsplit:最大的分割次数
flags:标志位,用于控制正则表达式的匹配方式。如是否区分大小写、是否多行匹配等
‘]
不指定分割次数
>>> re.split(r"\d+\s+","a2 b3 c4")
[‘a‘, ‘b‘, ‘c4
>>> print re.split(r"\d+","one1two2three3four4")
[‘one‘, ‘two‘, ‘three‘, ‘four‘, ‘‘]
指定分割次数
>>> re.split(r"\d+\s+","a2 b3 c4",2)
[‘a‘, ‘b‘, ‘c4‘]
>>> re.split(r"\d+","one1tow2three3four")
[‘one‘, ‘tow‘, ‘three‘, ‘four‘]
>>> re.split(r"\D+","one1tow2three3four",3)
[‘‘, ‘1‘, ‘2‘, ‘3four‘]
re.sub函数
语法:
re.sub(pattern, repl, string, count=0, flags=0)
返回一个被替换后的字符串,原字符串不变
参数说明:
pattern:匹配的正则表达式
repl:用于替换的字符串
string:要被替换的字符串
count:替换的次数,如果为0表示替换所有匹配到的字串,如果是1表示替换1次等,该参数必须是非负整数,默认为0。
flags:标志位,用于控制正则表达式的匹配方式。如是否区分大小写、是否多行匹配等
>>> re.sub(r"[a-z]+","XXX","ABC123ddd333",re.I)
‘ABC123XXX333‘
>>> re.sub(r"[a-z]+","XXX","ABC123ddd333",1,re.I)#只替换一次
‘XXX123ddd333‘
手机号码后四位替换成xxxx
>>> re.sub(r"\d{4}$","xxxx","13510163294")
‘1351016xxxx‘
字母去重
将字符串中连续出现的同个字母去重,如"abbbcccbba" -> "abcba"
>>> re.sub(r"([a-z])(\1)+",r"\1","abbbcccbba")
‘abcba‘
>>> re.sub(r"([a-z])(\1+)",r"\1","abbbcccbba")
‘abcba‘
匹配过程:
([a-z])为一个分组,匹配一个字母,\1引用分组,匹配和前面一样的字母
([a-z])(\1+) 整体匹配至少两个一样的字母;
repl 替换字符串 为函数
import re
def multiply(m):
# 将分组0的值转成整型
v = int(m.group(0))#匹配对象调用group()得到匹配的数字
# 将分组0的整型值乘以2,然后返回
return str(v * 2)
# 使用multiply方法作为第二个参数,根据正则表达式对象搜索匹配每个数字得到的匹配对象作为参数传入multiply函数,处理后将返回结果替换为相应字符串
result = re.sub("\d+", multiply, "10 20 30 40 50")
print result
执行结果:
re.subn函数
返回匹配内容和匹配次数的元组
语法:
re.subn(pattern, repl, string, count=0, flags=0)
pattern:匹配的正则表达式
repl:用于替换的字符串
string:要被替换的字符串
count:替换的次数,如果为0表示替换所有匹配到的字串,如果是1表示替换1次等,该参数必须是非负整数,默认为0。
flags:标志位,用于控制正则表达式的匹配方式。如是否区分大小写、是否多行匹配等
>>> re.subn(r"\d+","X","1A2B3C")
(‘XAXBXC‘, 3)
正则匹配对象的属性和方法
pos属性
该属性表示文本中正则表达式开始搜索的索引。值与Pattern.match()和Pattern.seach()方法中的开始位置相同
>>> m = re.match(r"\d+","1b2c3")
>>> m.pos
0
>>> m = re.search(r"\d+","a1b2c3")
>>> m.pos
0
endpos属性
该属性表示文本中正则表达式结束搜索的索引。值与Pattern.match()和Pattern.seach()方法中的开始位置相同
>>> m = re.match(r"\d+","1b2c3")
>>> m.endpos
5
>>> m = re.search(r"\d+","1b2c3")
>>> m.endpos
5
lastindex属性
该属性表示最后一个被捕获的分组索引从1开始。如果没有被捕获的分组,将为None。
>>> m = re.search(r"(\d+).*(!)","1a2b3c!")
>>> print m.lastindex
2
lastgroup属性
该属性表示最后一个被捕获的分组别名。如果这个分组没有别名或者没有被捕获的分组,将为None
>>> m = re.match(r‘(\w+)! (\w+)(?P<sign>.*)‘, ‘Hi! gloryroad!‘)
>>> print m.lastgroup
Sign
group([group1, ...]) 方法
获得一个或多个分组截获的字符串;指定多个参数时将以元组形式返回。group1可以使用编号也可以使用别名;编号0代表匹配的整个子串;默认返回group(0);没有截获字符串的组返回None;截获了多次的则返回最后一次截获的子串。
>>> m = re.search(r"(\d+)([a-z]+)","1one2two3three4four")
>>> m.group(0)
‘1one‘
>>> m.group(1)
‘1‘
>>> m.group(2)
‘one‘
>>> m.group(1,2)
(‘1‘, ‘one‘)
>>> m.group(1,1,2)#指定多个分组编号返回匹配内容的元组
(‘1‘, ‘1‘, ‘one‘)
分组嵌套
>>> m = re.search(r"(a(b)c)","abcdefg")
>>> m.group()
‘abc‘
>>> m.group(1)#最外层分组编号是1
‘abc‘
>>> m.group(2)
‘b‘
>>> m.group(1,2)
(‘abc‘, ‘b‘)
>>> m.group(1,2,1)
(‘abc‘, ‘b‘, ‘abc‘)
groups([default=None])方法
返回一个元组,元组内容是每个分组匹配的内容,相当于调用group(1,2,…last)
>>> m = re.search(r"(a(b)c)d","abcdefg")
>>> m.groups()#这个有括号
(‘abc‘, ‘b‘)
Start方法
返回指定的组截获的子串在string中的起始索引(子串第一个字符的索引)。默认为第0组。
>>> m = re.search(r"\d+","aaddfs5")
>>> m.start()
6
>>> m = re.search(r"(a(b)c)","abcdefg")
>>> m.start()
0
end方法
返回指定的组截获的子串在string中的结束索引(子串最后一个字符的索引)。group默认值为0
>>> m = re.search(r"\d+","ab123cd")
>>> m.start()
2
>>> m.end()
5
>>> m
<_sre.SRE_Match object; span=(2, 5), match=‘123‘>
span方法
该方法表示以元组的形式返回 (start(group), end(group)),即某个分组的匹配文字内容在被匹配字符串的开始索引位置和结束索引位置
>>> m = re.search(r"\d+","ab123cd")
>>> m.start()
2
>>> m.end()
5
>>> m.span()
(2, 5)
expand(template)方法
将匹配到的分组代入template中然后返回。template中可以使用\id或\g<id>、\g<name>
引用分组,但不能使用编号0。\id与\g<id>是等价的;但\10将被认为是第10个分组,如果你想表达\1之后是字符‘0‘,只能使用\g<1>0。
>>> m = re.search(r"(\w+)!\s(\w+)\s(\w+)","HMan! gloryroad train")
>>> m.group()
‘HMan! gloryroad train‘
>>> m.expand(r"result: \3 \2 \1")
‘result: train gloryroad HMan‘
>>> m.expand(r"result: \g<1> \g<2> \g<1>")
‘result: HMan gloryroad HMan‘
groupdict([default=None])方法
该函数的作用是,将所有匹配到并且指定了别名的分组,以别名为key,匹配到的字串为value,存于字典中,然后返回这个字典。如果表达式中未设置别名分组,就会返回一个空字典
>>> m = re.match(r"(?P<group1>.*)is(?P<group2>.*)",line)
>>> m.group()
‘This is the last one‘
>>> m.groups()
(‘This ‘, ‘ the last one‘)
>>> m.groupdict()
{‘group1‘: ‘This ‘, ‘group2‘: ‘ the last one‘}
.* 正则的贪婪性
>>> s = ".*g3jl"
>>> res = re.match(r".*",s).group()
>>> res
‘.*g3jl‘
点(.)表示匹配除换行符以外的任意一个字符,星号(*)表示匹配前面一个字符0次或多次,这两符号一起使用表示匹配除换行符以为的任意多个字符,也就是说点星(.*)组合时,它们会尽可能多的去匹配满足条件的字符,这就是点星(.*)的贪婪性,所以就会出现上面的结果
只有当正则表达式中要匹配的字符数小于等于原字符串中的字符数时,才有可能匹配出结果。并且 “.*” 在匹配的过程中会回溯,先匹配0次,如果整个表达式能匹配成功,再匹配一次,如果还是能匹配,那就匹配两次,这样一次次试下去,直到不能匹配成功时,返回最近一次匹配成功的结果,这就是”.*”的贪婪性
>>> line = "this a134gwordgtest"
>>> m = re.match(r".*a.*g",line)
#.*g匹配134g后还会取匹配wordg
>>> m.group()
‘this a134gwordg‘
>>> m = re.match(r".*a.*?g",line)#加?后只匹配一次
>>> m.group()
‘this a134g‘
正则表达式—修饰符
re.I 全写(re.IGNORECASE),表示使匹配时,忽略大小写
re.L 全写(re.LOCALE),使预定字符类 \w \W \b \B \s \S 取决于当前区域设定
re.M 全写(re.MULTILINE),多行匹配,影响 ^ 和 $的行为
re.S 全写(re.DOTALL),使点(.)匹配包括换行在内的所有字符
re.U 全写(re.UNICODE),根据Unicode字符集解析字符。这个标志影响\w \W \b \B \s \S \d \D
re.X 全写(re.VERBOSE),该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释
re.I
忽略大小写匹配
编译模式
>>> pattern = re.compile(r"[a-z]+",re.I)
>>> pattern.match("AbC123")
<_sre.SRE_Match object; span=(0, 3), match=‘AbC‘>
>>> pattern.match("AbC123").group()
‘AbC‘
直接匹配模式
>>> re.match(r"[a-z]+","XYZ12",re.I)
<_sre.SRE_Match object; span=(0, 3), match=‘XYZ‘>
>>> re.match(r"[a-z]+","XYZ12",re.I).group()
‘XYZ‘
re.M
多行匹配,影响 ^ 和 $的行为
未使用re.M匹配多行文字最后一行的结尾 ,会把字符串当成一个整体来看待
>>> s = """
... 123 abc
... 456 xyz
... 789 ABC
... """
>>> re.search(r"[a-zA-Z]+$",s).group()
‘ABC‘
使用re.M,会匹配多行文字的每行结尾
>>> re.search(r"[a-zA-Z]+$",s,re.M).group()
‘abc‘
#因为使用的search,在第一行结尾找到就不会继续匹配了,所以只输出abc
#不使用re.M只会匹配多行内容最后一行的结尾
>>> re.findall(r"[a-zA-Z]+$",s)
[‘ABC‘]
#使用re.M可以匹配多行内容每一行的结尾
>>> re.findall(r"[a-zA-Z]+$",s,re.M)
[‘abc‘, ‘xyz‘, ‘ABC‘]
#此处使用的findall所以会依次匹配每行的结尾,所以输出了每行的匹配字符
re.I | re.M结合使用
import re
p = re.compile(r‘^.*[a-z]+$‘, re.I|re.M)
string = """I am a Boy
Your a beautiful Girl
Right"""
matchResult = p.search(string)
if matchResult:
print matchResult.group()
else:
print "no string found!"
print p.findall(string) #这个对应结果第二行
执行结果:
re.S
使点(.)匹配包括换行在内的所有字符
>>> re.findall(r".","a \n bc",re.S)
[‘a‘, ‘ ‘, ‘\n‘, ‘ ‘, ‘b‘, ‘c‘]
re.X
此标志允许您编写正则表达式,看起来更好。在模式中的空白将被忽略,除非当在字符类或者前面非转义反斜杠,和,当一条线包含一个‘#‘既不在字符类中或由非转义反斜杠,从最左侧的所有字符之前,这种‘#‘通过行末尾将被忽略
以下两个正则表达式匹配的字符是一样的
a = re.compile(r"""\d + # the integral part
\. # the decimal point
\d * # some fractional digits""", re.X)
b = re.compile(r"\d+\.\d*")
>>> s = "ab 12 _ AB.cd.com"
>>> p = re.compile(r"""
... \w+
... \s+
... \d+
... \s+
... \w+
... \s+
... .*#匹配任意多个字符
... """,re.S|re.X)
>>> p.match(s)
<_sre.SRE_Match object; span=(0, 17), match=‘ab 12 _ AB.cd.com‘>
>>> p.match(s).group()
‘ab 12 _ AB.cd.com‘
分组
无名分组
分组就是用一对圆括号“()”括起来的正则表达式,匹配出的内容就表示一个分组。需要注意的是,有一个隐含的全局分组(就是索引号为0的分组),就是整个正则表达式匹配的结果。
s = u‘<div><a href="https://support.google.com/chrome/?p=ui_hotword_search" target="_blank">更多</a><p>dfsl</p></div>‘
print re.search(r"<a.*>(.*)</a>",s).group(1)
命名分组
命名分组就是给具体有默认分组编号的组另外再起一个别名,方便以后的引用。
命令分组的语法格式如下:
(?P<name>正则表达式)
语法格式中的字符P必须是大写的“P”,name是一个合法的标识符,表示分组的别名
>>> s = "ip=‘230.192.168.78‘,version=‘1.0.0‘"
>>> m = re.search(r"(?P<ip>\d+\.\d+\.\d+\.\d+)",s)
#括号定义了一个分组,?P<ip>定义分组别名为ip
>>> print m.group()
230.192.168.78
>>> print m.group("ip")#此处可以因为分组别名ip,要加引号
230.192.168.78
多个命名分组
>>> s = "phone,number,15817934235"
>>> m = re.match(r"(?P<first>\w+),(?P<second>\w+),(?P<third>\d+)",s)
>>> m.group()
‘phone,number,15817934235‘
>>> m.group(1)
‘phone‘
>>> m.group(2)
‘number‘
>>> m.group(3)
‘15817934235‘
>>> m.group("first")#取名为first分组的组
‘phone‘
>>> m.group("second")
‘number‘
>>> m.group("third")
‘15817934235‘
后向引用(就是引用分组)
正则表示式中,放在圆括号“()”中的表示是一个分组。然后我们就可以对整个组使用一些正则操作,例如重复操作符。
要注意的是,只有圆括号“()”才能用于形成分组,“ ”用于定义字符串,而“{}”用于定义重复操作。
当用“()”定义了一个正则表达式分组后,正则引擎就会把匹配的组按照顺序进行编号,然后存入缓存中。这样我们就可以在后面对已经匹配过的内容进行引用,这就叫后向引用。
后向引用的语法:
1、通过索引引用
\数字
\1表示引用第一个分组,\2引用第二个分组,以此类推,\n引用第n个组,而\0则表示引用整个被匹配的正则表达式本身。
2、通过命名分组名进行引用(如果有的话)
(?P=name)
字符P必须是大写的P,name表示命名分组的分组名。
注意:
这些引用都必须是在正则表达式中才有效,用于匹配一些重复的字符串。
通过分组编号进行引用
>>> s = ‘aaa111aaatestaaa
>>> m = re.match(r"(\w+)\d+(\1)\w+(\1)",s)
>>> m
<_sre.SRE_Match object at 0x0000000002573588>
>>> m.group()
‘aaa111aaatestaaa‘
>>> m.groups()
(‘aaa‘, ‘aaa‘, ‘aaa‘)
>>> m.group(1)
‘aaa‘
>>> m.group(2)
‘aaa‘
>>> m.group(3)
‘aaa‘
通过分组名进行引用
>>> s = ‘aaa111aaatestaaa
>>> m = re.match(r"(?P<first>a{3})\d+(?P=first)\w+(?P=first)",s)
>>> m.group()
‘aaa111aaatestaaa‘
>>> m.group("first")
‘aaa‘
>>> m.groups()
(‘aaa‘,)
示例2:
>>> re.search(r"\d+(?P<xx>[a-z]+)\s+(?P=xx)","12abc abc").group("xx")
‘abc‘
?P=xx 不是等于[a-z]+,而是等于前面分组匹配到的内容
需要注意的是:后面的(?P=XX)只是分组1即(?P<XX>[a-z]+)的引用,并不是分组2,?P=xx 不是等于[a-z]+,而是等于前面分组匹配到的内容,引用分组匹配的内容必须要与分组1的内容完全相同,否则匹配不到;
替换分组
>>> s = ‘abc.xyz‘
>>> re.sub(r"(.*)\.(.*)",r"\2.\1",s)
‘xyz.abc‘
>>> re.sub(r"(\w+).(\w+)",r"\2.\1",s)
‘xyz.abc‘
扩展表示法
前向肯定(?<=pattern)
前向肯定断言表示你希望匹配的字符串前面是pattern匹配的内容时,才匹配字符串,但是不输出前向肯定表达式匹配的内容;前向肯定表达式放在需要匹配字符串正则表达式前面
前向肯定断言括号中的正则表达式必须是能确定长度的正则表达式,比如\w{3},而不能写成\w*或者\w+或者\w?等这种不能确定个数的正则模式符
只有当abc前面是两个数字才匹配
>>> re.search(r"(?<=\d{2})abc","1abc 45abc").group()#abc在括号外
‘abc‘
>>> re.search(r"(?<=\d{2})abc","1abc 45abc")
<_sre.SRE_Match object; span=(7, 10), match=‘abc‘>
#2处的数字只能是固定的数,不能是+等数量词
只有当前面是两个数字时候才匹配
>>> re.search(r"(?<=\d{2})\w+","1abc34xyz")
<_sre.SRE_Match object; span=(6, 9), match=‘xyz‘>
>>> re.search(r"(?<=\d{2})\w+","1abc34xyz").group()
‘xyz‘
>>> re.findall(r"(?<=\d{2})\w+","1abc34xyz")#abc前面只有一个数字,不匹配
[‘xyz‘]
只有当前面是一个大写字母时候才匹配多个数字
>>> re.search(r"(?<=[A-Z])\d+","a123A78 llldd").group()
‘78‘
前向否定(?<!pattern)
前向否定断言表示你希望匹配的字符串前面不是pattern匹配的内容时,才匹配字符串,但是不输出前向否定表达式匹配的内容,
前面不是两个数字才匹配,所以只匹配了abc
>>> re.search(r"(?<!\d{2})[a-z]+","12a XYZ",re.I).group()
‘XYZ‘
>>> re.search(r"(?<!\d{2})[a-z]+","13a2abc").group()
‘abc‘
前面不是一个小写字母的才匹配多个数字
>>> re.findall(r"(?<![a-z])\d+","a123X456 ...")
[‘23‘, ‘456‘]
>>> re.findall(r"(?<![a-z])\d+","a23 [email protected]")
[‘3‘, ‘4‘, ‘4‘]
>>> re.search(r"(?<![a-z])\d+","a23 [email protected]").group()
‘3‘
后项肯定(?=pattern)
后向肯定断言表示你希望匹配的字符串后面是pattern匹配的内容时,才匹配字符串,但是不输出后向肯定表达式匹配的内容;后向肯定表达式需要放在需匹配正则表达式后面
后面是数字才匹配
>>> re.search(r"[a-z](?=\d+)","a1 b c35").group()
‘a‘
>>> re.findall(r"[a-z](?=\d+)","a1 b c35 kk")
[‘a‘, ‘c‘]
一个密码匹配的示例:
#至少包含6个字符,至少一个字母、一个数字,只能包含字母数字
import re
def check_password(passwd):
if re.match(r‘^(?=.*[A-Za-z])(?=.*[0-9])[A-Za-z0-9]{6,}$‘,passwd):
print ("password %s strong" %passwd)
else:
print ("password %s is weak" %passwd)
check_password("dkslfkj1")
check_password("abc")
check_password("123")
check_password("1233abc")
check_password("abc123")
– ?=表示匹配表达式
后项否定(?!pattern)
后向肯定断言表示你希望匹配的字符串后面不是pattern匹配的内容时,才匹配字符串,但是不输出后向否定表达式匹配的内容;后向否定表达式需要放在需匹配正则表达式后面
后面不是数字匹配
>>> re.search(r"[a-z]+(?!\d+)","abc12 xyz")
<_sre.SRE_Match object; span=(0, 2), match=‘ab‘>
>>> re.findall(r"[a-z]+(?!\d+)","abc12 xyz")
[‘ab‘, ‘xyz‘]
>>> re.search(r"\w+(?!\d+)","abc123 XYZ").group()
‘abc123‘
之所以输出abc123,而不是abc是因为前面的+是贪婪式的,会尽可能多的匹配
后面不是5的匹配
>>> re.search(r"[A-Z]{3}(?!5)","ABC5XYZ1ZZZ4").group()
‘XYZ‘
>>> re.findall(r"[A-Z]{3}(?!5)","ABC5XYZ1ZZZ4")
[‘XYZ‘, ‘ZZZ‘]
注意:
前向肯定与前向否定匹配规则后面的量词只能用指定次数{n},不能用*、+、?、{m,n}等未明确次数的规则;
但是后向肯定与后向否定匹配跪着后面的量词可以用指定次数{n},也可以用*、+、?、{m,n}等未明确次数的规则;
示例:
>>> re.findall(r"(?m)^\s+(?!noreply|postmaster)(\w+)",
... """
... [email protected]
... [email protected]
... [email protected]
... [email protected]
... [email protected]
... """
... )
[‘sale‘, ‘eng‘, ‘admin‘]
Findall只包含一个分组,只返回分组的匹配内容
(?m)表示多行匹配,每一行都会匹配
^\s+ 表示匹配开头多个空格
(?!noreply|postmaster) 表示不是noreply 、postmaster才匹配
(?iLmsux)
忽略大小写
>>> re.search(r"(?i)[a-z]+","123ABCa").group()
‘ABCa‘
.匹配\n换行
>>> re.match(r"(?s)\w+.\d+","abc\n123").group()
‘abc\n123‘
多行匹配模式
>>> re.findall(r"(?m)[a-z]+","abc\nxyz\n123")
[‘abc‘, ‘xyz‘]
忽略空白、注释
(?:...)非捕获模式
>>> re.findall(r"a(?:\d+)b.+a(?:\d+)b", "a23b\na34b", re.S)
[‘a23b\na34b‘]#由于此处使用非捕获模式,所以不会返回列表,而是返回匹配
>>> re.findall(r"a(\d+)b.+a(\d+)b", "a23b\na34b", re.S)#多个括号,返回一个列表
[(‘23‘, ‘34‘)]
示例:
在下面的string中匹配到‘asd‘的多个重复‘asdasdasdasdasdasdasd‘而不是单个‘asd‘
string=‘asdasdasdasdasdasdasddasfdhgasghsd‘
>>> string = ‘asdasdasdasdasdasdasddasfdhgasghsd‘
>>> print(re.findall(r‘((?:asd)+)‘, string))
[‘asdasdasdasdasdasdasd‘]
#(?:asd)+ 是正则的一种不存分组的语法, 它具有2个用途, 将`asd`看成一个样式整体, 所以当我们用+时, 就能代表多个asd
# () 最外层的括号就是将匹配的结果存入分组, 与上面不同的就是, 少了`?:`, 因为没有这个, 所以它能存到分组
# 所以整体的结果就是: 将多个asd匹配, 并存入分组, 然后在re.findall的结果就能看到了
特殊字符的使用
\b匹配单词的边界
>>> re.findall(r"\b[a-zA-Z]+\b","i am a good boy")
[‘i‘, ‘am‘, ‘a‘, ‘good‘, ‘boy‘]
\B匹配非单词边界
>>> re.search(r"\Bthe\B","abthecd").group()
‘the‘
IP匹配正则
pattern = re.compile(r‘^(([1-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]).){3}([1-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])$‘)
密码匹配规则:
密码强度正则表达式 – 必须包含大写字母,小写字母和数字,至少8个字符等
需要一个密码强度正则表达式在用户注册时校验用户密码强度:密码至少8个字符,包括1个大写字母,1个小写字母和1个数字或特殊字符,例如#,?,!。网上搜索了一些解决方案分享给大家。
方案一
至少8-16个字符,至少1个大写字母,1个小写字母和1个数字,其他可以是任意字符:
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$/
或者:
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[\s\S]{8,16}$/
其中 [\s\S] 中的\s空白符,\S非空白符,所以[\s\S]是任意字符。也可以用 [\d\D]、[\w\W]来表示。
至少8个字符,至少1个大写字母,1个小写字母和1个数字,不能包含特殊字符(非数字字母):
^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$
至少8个字符,至少1个字母,1个数字和1个特殊字符:
^(?=.*[A-Za-z])(?=.*\d)(?=.*[[email protected]$!%*#?&])[A-Za-z\[email protected]$!%*#?&]{8,}$
至少8个字符,至少1个大写字母,1个小写字母和1个数字:
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$
至少8个字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符:
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[[email protected]$!%*?&])[A-Za-z\[email protected]$!%*?&]{8,}
最少8个最多十个字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符:
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[[email protected]$!%*?&])[A-Za-z\[email protected]$!%*?&]{8,10}
方案二
还有,你可以使用这个正则表达式:
^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#[email protected]$%^&*-]).{8,}$
这个正则表达式将强制执行这些规则:
至少1个大写字母English letter,(?=.*?[A-Z])
至少1个小写英文字母,(?=.*?[a-z])
至少1位数字,(?=.*?[0-9])
至少有1个特殊字符,(?=.*?[#[email protected]$%^&*-])
最小8个长度.{8,}
方案三
正则表达式没有AND运算符,所以编写正则表达式与有效密码匹配是非常困难的,当有效性被某些东西和其他东西等定义时…
但是,正则表达式确实有1个OR运算符,所以只需应用DeMorgan的定理,并编写1个与无效密码相匹配的正则表达式:
任何少于8个字符或任何没有数字或任何没有大写字母或任何没有小写字母或任何没有特殊字符的任何东西。
所以:^(.{0,7}|[^0-9]*|[^A-Z]*|[^a-z]*|[a-zA-Z0-9]*)$,如果有什么匹配的话,这是1个无效的密码。
方案四
由于特殊字符仅限于键盘中的特殊字符,因此可用于任何特殊字符:
^(?=.*?[A-Z])(?=(.*[a-z]){1,})(?=(.*[\d]){1,})(?=(.*[\W]){1,})(?!.*\s).{8,}$
这个正则表达式将强制执行这些规则:
– 至少1个大写英文字母
– 至少1个小写英文字母
– 至少1位数字
– 至少1个特殊字符
– 最少8个长度
方案五
根据我的情况,我遇到了最受欢迎的答案。例如,我的验证失败,其中包含;或[等字符。我对 white-listing 我的特殊字符不感兴趣,所以我用[^\w\s]作为测试 – 简单地把非字符(包括数字)和非空格字符放在一起。总而言之,这是对我有用的
至少8字符
至少1数字字符
至少1小写字母
至少1大写字母
至少1特殊字符/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^\w\s]).{8,}$/ 简单演示涵盖各种情况
方案六
导入javascript文件jquery.validate.min.js。
您可以使用此方法:
JavaScript 代码:
$.validator.addMethod("pwcheck", function (value) {return /[\@\#\$\%\^\&\*\(\)\_\+\!]/.test(value) && /[a-z]/.test(value) && /[0-9]/.test(value) && /[A-Z]/.test(value)
});
至少1个大写英文字母
至少1个小写英文字母
至少1位数字
至少1个特殊字符
方案七
尝试这个:
– 最少6个字符
– 至少有1个大写字符
– 至少1个小写字符
– 至少1个特殊字符
表达式:
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[[email protected]$!%*?&.])[A-Za-z\[email protected]$!%*?&.]{6, 20}/
可选特殊字符:
至少1个特殊字符
至少1个数字
特殊字符是可选的
最少6个字符,最多16个字符
表达式:
/^(?=.*\d)(?=.*[a-zA-Z]).{6,20}$/
如果不需要最小和最大条件,则删除.{6, 16}
– 6是最小字符数限制
– 20是最大字符限制
– ?=表示匹配表达式
练习:
1 找出一个字符串中是否有连续的5个数字
>>> re.search(r"\d{5}","a77788b").group()
‘77788‘
2 找出一个字符串中的连续5个数字,要求数字前后必须是非数字
>>> re.search(r"\D\d{5}\D|^\d{5}\D|\D\d{5}|^\d{5}$","77788").group()
‘77788‘
>>> re.search(r"\D\d{5}\D|^\d{5}\D|\D\d{5}|^\d{5}$","77788").group()
‘77788‘
>>> re.search(r"\D\d{5}\D|^\d{5}\D|\D\d{5}|^\d{5}$","a77788").group()
‘a77788‘
>>> re.search(r"\D\d{5}\D|^\d{5}\D|\D\d{5}|^\d{5}$","77788b").group()
‘77788b‘
>>> re.search(r"\D\d{5}\D|^\d{5}\D|\D\d{5}|^\d{5}$","a77788b").group()
‘a77788b‘
3、统计一个文件的单词数量
>>> with open("e:\\python\\4.txt") as file_obj:
... content = file_obj.read()
... word_list = re.findall(r"\b[a-zA-Z]+\b",content)
... print(len(word_list))
...
40
4、把a1b23c4d非字符内容拼成一个字符串
>>> "".join(re.findall(r"\d+","a1b23c4d"))
‘1234‘
5、取最后一个字母
>>> re.findall(r"[a-zA-Z]","ab23agdf")[-1]
‘f‘
6、找出一个字符串中的所有数字
>>> re.findall(r"\d+","1df3dd55d55")
[‘1‘, ‘3‘, ‘55‘, ‘55‘]
7、把一个字符串中的所有字母找出并拼成一个字符串
>>> "".join(re.findall(r"[a-z]","1df3dd55d55",re.I))
‘dfddd‘
8、输出句子中的所有单词
>>> re.findall(r"\b[a-zA-Z]+\b","i will a strong man")
[‘i‘, ‘will‘, ‘a‘, ‘strong‘, ‘man‘]
9、匹配字符串里面的字典
str = """
var localCity = [{
provinceCode: "110000",
cityCode: "110100",
text: "北京",
dpt: ‘20127‘,
carNo: ‘京A‘,
pName: ‘北京市‘,
cName: ‘北京市‘
},
{
provinceCode: "310000",
cityCode: "310100",
text: "上海",
dpt: ‘2022003‘,
carNo: ‘沪A‘,
pName: ‘上海市‘,
cName: ‘上海市‘
}]
"""
>>> re.findall(r"{.*?}",str,re.S|re.M)#因为有换行所以点(.)要匹配\n,并且要多行模式匹配,?抑制.*匹配后面的}
[‘{\nprovinceCode: "110000",\ncityCode: "110100",\ntext: "北京",\ndpt: \‘20127\‘,\ncarNo: \‘京A\‘,\npName: \‘北京市\‘,\ncName: \‘北京市\‘\n},\n{\nprovinceCode: "310000",\ncityCode: "310100",\ntext: "
上海",\ndpt: \‘2022003\‘,\ncarNo: \‘沪A\‘,\npName: \‘上海市\‘,\ncName: \‘上海市\‘\n}‘]
10、找出字符中的最大数字
>>> s = "1dsf343d9988"
#findall 全局匹配,然后找最大值
>>> max([int(num) for num in re.findall(r"\d+",s)])
9988
#findall全局匹配后,排序后,找最大值
>>> sorted([int(num) for num in re.findall(r"\d+",s)])[-1]
9988
#利用非数字,正则拆分出数字,求最大值
>>> max([int(num) for num in re.split(r"\D+",s)])
9988
#字符串中所有非数字替换成空白,然后拆分成数字列表
>>> max([int(num) for num in re.sub(r"\D+"," ",s).split()])
9988
#普通方法
>>> for v in s:
... if not v.isdigit():
... s = s.replace(v," ")
...
>>> max([int(v) for v in s.split()])
9988
11、匹配不包含连续字符串abc的单词。s=‘abcddd qweabee ddabc abc cba’
s=‘abcddd qweabee ddabc abc cba’
>>> [m.group() for m in re.finditer(r"\b((?!abc)\w)+\b",s)]
[‘qweabee‘, ‘cba‘]
如果用findall需要在正则表达式外加一个外层分组,findall只返回分组的内容,如果有分组
>>> re.findall(r"\b((?!abc)\w)+\b",s)
[‘e‘, ‘a‘]
>>> re.findall(r"(\b((?!abc)\w)+\b)",s)
[(‘qweabee‘, ‘e‘), (‘cba‘, ‘a‘)]
应该是没理解(?!abc)的意义,(?!abc)匹配的是一个位置,不占用任何字符.
(?!abc)的意义就是从当前匹配到的位置起,接下来不是一个字符"a"接着一个字符"b"接着一个字符"c".(?!abc)\w的意义是用(?!abc)来限定\w的匹配,从\w的位置起不能出现一个字符"a"接着一个字符"b"接着一个字符"c".((?!abc)\w)+就是多个被限定的\w组成的单词,这个单词中肯定不会出现"abc".
再举个例子:
(?!office)[a-z]+2000:不匹配"office2000",匹配"windows2000"
(?!a11)a:匹配"a10a11a12"中的第一个和第三个"a"
12、统计文章的字母个数
>>> with open("d:\\a.txt") as file_obj:
... print(len(re.findall(r"[a-zA-Z]",file_obj.read())))
...
1
13、统计文章数字个数
>>> with open("d:\\a.txt") as file_obj:
... print(len(re.findall(r"\d",file_obj.read())))
...
1
14、统计文章中的单词个数
>>> with open("d:\\a.txt") as file_obj:
... print(len(re.findall(r"\b[a-z]+\b",file_obj.read(),re.I)))
...
1
16、获取某个网页的所有链接
#coding=utf-8
import re
import requests
res = requests.get("https://www.sogou.com")
print(res.text)
links = re.findall(r‘href="(.*?)"‘,res.text)
print(links)
print(len(links))
17、?删除文章中所有数字
>>> with open("d:\\a.txt","r+") as file_obj:
... new = re.sub(r"\d","",file_obj.read())
... file_obj.seek(0,0)
... file_obj.write("")
... file_obj.seek(0,0)
... file_obj.write(new)
...
0
0
0
7
18、?删除后统计一下删除组数
>>> re.subn(r"\d+","","a123 b456 c789d")[1]
3
19、?匹配一个ip
IP地址是一个32位的二进制数,通常被分割为4个“8位二进制数”(也就是4个字节)。IP地址通常用“点分十进制”表示成(a.b.c.d)的形式,其中,a,b,c,d都是0~255之间的十进制整数。例:点分十进IP地址(100.4.5.6),实际上是32位二进制数(01100100.00000100.00000101.00000110)
pattern = re.compile(r‘^(([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.){3}([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])$‘)
pattern = re.compile(r‘^((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.){3}(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])$‘)
>>> pattern.match("0.0.0.0")
<_sre.SRE_Match object; span=(0, 7), match=‘0.0.0.0‘>
>>> pattern.match("1.20.245.255")
<_sre.SRE_Match object; span=(0, 10), match=‘1.20.245.2‘>
20、?统计开头不是a的所有单词
>>> re.findall(r"\b(?!a)[a-zA-Z]+\b","abc cdea kkk")
[‘cdea‘, ‘kkk‘]
>>> with open("d:\\a.txt","r+") as file_obj:
... print(re.findall(r"\b[b-zA-Z][a-zA-Z]+\b",file_obj.read()))
...
[‘good‘, ‘boy‘]
21、?匹配1900年到2999年
>>> re.match(r"(19\d{2}|2\d{3})年","1900年")
<_sre.SRE_Match object; span=(0, 5), match=‘1900年‘>
以上是关于正则学习的主要内容,如果未能解决你的问题,请参考以下文章