正则表达式
正则的元字符
w3c的零基础教程:https://www.w3cschool.cn/regexp/zoxa1pq7.html
正则表达式30分钟入门教程:http://deerchao.net/tutorials/regex/regex.htm
正则速查:http://www.uedsc.com/lookup-tables.html
'*','+'和'?' 表示字符重复出现的次数,分别表示“零或更多”,“一次或更多”还有“零次或一次”。
'*','+'和'?' 相当于"{0,}","{1,}"和"{0,1}"。
"ab*":表示一个字符串有一个a后面跟着零个或若干个b。("a", "ab", "abbb",……);
"ab+":表示一个字符串有一个a后面跟着至少一个b或者更多;#贪婪匹配,尽可能多的匹配
"ab?":表示一个字符串有一个a后面跟着零个或者一个b;#非贪婪匹配,尽可能少的匹配
"a?b+$":表示在字符串的末尾有零个或一个a跟着一个或几个b。
"ab{2}":表示一个字符串有一个a跟着2个b("abb");
"ab{2,}":表示一个字符串有一个a跟着至少2个b;
"ab{3,5}":表示一个字符串有一个a跟着3到5个b。
"hi¦hello":表示一个字符串里有"hi"或者"hello";
"(b¦cd)ef":表示"bef"或"cdef";
"(a¦b)*c":表示一串"a""b"混合的字符串后面跟一个"c";
[]方括号是字符集合,表示匹配方括号中所包含的任意一个字符
中括号里的^称为脱字符,表示不匹配集合中的字符
"a.[0-9]":表示一个字符串有一个"a"后面跟着一个任意字符和一个数字;
"^.{3}$":表示有任意三个字符的字符串(长度为3个字符);
"[ab]":表示一个字符串有一个"a"或"b"(相当于"a¦b");
"[a-d]":表示一个字符串包含小写的'a'到'd'中的一个(相当于"a¦b¦c¦d"或者"[abcd]");
"^[a-zA-Z]":表示一个以字母开头的字符串;
"[0-9]%":表示一个百分号前有一位的数字;
",[a-zA-Z0-9]$":表示一个字符串以一个逗号后面跟着一个字母或数字结束。
"%[^a-zA-Z]%"表示两个百分号中间不应该出现字母
[^good] 匹配除了good这几个字母以外的所有字符,
[^0-9] 匹配所有的非数字字符
'''
^ 行首匹配,和在[]里的^不是一个意思,注意:写在最前面,表示一个字符串的开始
$ 行尾匹配,注意:写在正则最后面,表示一个字符串的结束
. 匹配除换行符以外的任意字符
说明:下方的x,y均为假设的普通字符,n,m(非负整数),不是正则表达式的元字符
(xyz) 匹配小括号内的xyz(作为一个整体去匹配)
x? 匹配0个或者1个x
x* 匹配0个或者任意多个x(.*表示匹配0个或者任意多个字符(换行符除外))
x+ 匹配至少一个x
x{n,} 匹配至少n个x
x{n} 匹配确定的n个x(n是一个非负整数)
x{n,m} 匹配至少n个最多m个x,注意n<=m
x|y |表示或,匹配的是x或y
\d 匹配数字,效果同[0-9]
\D 匹配非数字字符,效果同[^0-9]
\w 匹配数字,字母和下划线,效果同[0-9a-zA-Z_]
\W 匹配非数字,字母和下划线,效果同[^0-9a-zA-Z_ ]
\s 匹配任意的空白符(空格、回车、换行、制表、换页),效果同[\r\n\t\f]
\S 匹配任意的非空白符,效果同[^\f\n\r\t]
'''
注意:
通常情况下?与*或者是+一起连用,来起到一个限制贪婪匹配的作用
*与+一般情况下与“.”,代表匹配任意多个任意字符
'''
\A 匹配字符串开始,它和^的区别是,\A只匹配整个字符串的开头,即使在re.M模式(,flags=re.m)下也不会匹配其他行的行首
\Z 匹配字符串结束,它和$的区别是,\Z只匹配整个字符串的结束,即使在re.M模式下也不会匹配其它行的行尾
注意:若不指定re.M模式,则^与\A,$与\Z匹配结果相同。
\b 匹配一个单词的边界,也就是指单词和空格的位置,'er\b'可以匹配never,不能匹配nerve。
注意:当\b添加在单词左边的时候,它会从单词左边的边界开始匹配,
当\b添加添加单词的右边的时候,它会从单词的右边边界开始匹配.
若想匹配整个单词,我们需要给这个单词左右两边都添加\b
\B 匹配非单词边界
#注意:当\B写在左边,它表示非左边边界开始匹配
当\B写在右边,它表示非右边边界开始匹配
若单词两边都有\B,它只匹配单词非边界中含有字符。
'''
为了逐字表达,你必须在"^.$()¦[]+?{"这些字符前*加上转义字符\''。
请注意在方括号中,不需要转义字符。
贪婪与懒惰
当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。
以这个表达式为例:a.b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪*匹配。
有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。
这样.?*就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。现在看看懒惰版的例子吧:
a.?b匹配最短的,以a开始,以b结束的字符串。如果把它应用于aabab*的话,它会匹配aab(第一到第三个字符)和ab(第四到第五个字符)。
为什么第一个匹配是aab(第一到第三个字符)而不是ab(第二到第三个字符)?简单地说,因为正则表达式有另一条规则,比懒惰/贪婪规则的优先级更高:最先开始的匹配拥有最高的优先权。
代码/语法 | 说明 |
---|---|
*? | 重复任意次,但尽可能少重复 |
+? | 重复1次或更多次,但尽可能少重复 |
?? | 重复0次或1次,但尽可能少重复 |
{n,m}? | 重复n到m次,但尽可能少重复 |
{n,}? | 重复n次以上,但尽可能少重复 |
练习题
'''功能1:提取:you...man'''
str1 = "you are a good man,you are a nice man ,you are a great man,you are a..."
print(re.findall(r"you.*?\bman\b",str1))
#\b的用法
str1 = "good man,you are a nice man ,you are a great man,you are a..."
print(re.findall(r"\bman\b",str1)) # ['man', 'man', 'man']
'''功能2:/* part1 */ /* part2 */'''
print(re.findall(r"/\*.*?\*/",r"/* part1 */ /* part2 */"))#\转义字符给*转义
'''功能3:判断电话号码是否以134开头'''
print(re.findall("^134\d{8}$","12345678901"))
'''
功能4:判断QQ号码是否合法:
1.位数6~10
2.全部是数字
3.不能以0开头
'''
^[1-9]\d{5,9}$
'''
功能5:校验普通电话、传真号码:可以“+”或数字开头,可含有“-” 和 “ ”
'''
/^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$/
#可以匹配的字符串如:+123 -999 999 ; +123-999 999 ;123 999 999 ;+123 999999等
'''功能6:校验URL'''
/^http[s]{0,1}:\/\/.+$/
或 /^http[s]{0,1}:\/\/.{1,n}$/ (表示url串的长度为length(“https://”) + n )
'''功能7:校验密码:只能输入6-20个字母、数字、下划线'''
^(\w){6,20}$
#功能8:对用户输入的数据进行限制6位0或者1,若不是则重新输入。
def test_num():
while True:
num = input("请输入一位6位的中奖号码(0/1)组成:")
res = re.findall("^[01]{6}$", num)
if len(res) == 1:
return num
else:
print("输入非法,请重新输入。。。")
continue
'''
功能9
1.身份证正则
2.电话号码的正则
3.邮箱正则
封装成一个功能模块。
'''
import re
def checkIdcard(idcard):
Errors = ['验证通过!', '身份证号码位数不对!', '身份证号码出生日期超出范围或含有非法字符!', '身份证号码校验错误!', '身份证地区非法!']
area = {"11": "北京", "12": "天津", "13": "河北", "14": "山西", "15": "内蒙古", "21": "辽宁", "22": "吉林", "23": "黑龙江",
"31": "上海",
"32": "江苏", "33": "浙江", "34": "安徽", "35": "福建", "36": "江西", "37": "山东", "41": "河南", "42": "湖北", "43": "湖南",
"44": "广东", "45": "广西", "46": "海南", "50": "重庆", "51": "四川", "52": "贵州", "53": "云南", "54": "西藏", "61": "陕西",
"62": "甘肃", "63": "青海", "64": "宁夏", "65": "新疆", "71": "台湾", "81": "香港", "82": "澳门", "91": "国外"}
idcard = str(idcard)
idcard = idcard.strip()
idcard_list = list(idcard)
# 地区校验
key = idcard[0: 2] # TODO: cc 地区中的键是否存在
if key in area.keys():
if (not area[(idcard)[0:2]]):
return Errors[4]
else:
return Errors[4]
# 15位身份号码检测
if (len(idcard) == 15):
if ((int(idcard[6:8]) + 1900) % 4 == 0 or (
(int(idcard[6:8]) + 1900) % 100 == 0 and (int(idcard[6:8]) + 1900) % 4 == 0)):
erg = re.compile(
'[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}$') # //测试出生日期的合法性
else:
ereg = re.compile(
'[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}$') # //测试出生日期的合法性
if (re.match(ereg, idcard)):
return Errors[0]
else:
return Errors[2]
# 18位身份号码检测
elif (len(idcard) == 18):
# 出生日期的合法性检查
# 闰年月日:((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))
# 平年月日:((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))
if (int(idcard[6:10]) % 4 == 0 or (int(idcard[6:10]) % 100 == 0 and int(idcard[6:10]) % 4 == 0)):
ereg = re.compile(
'[1-9][0-9]{5}(19[0-9]{2}|20[0-9]{2})((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}[0-9Xx]$') # //闰年出生日期的合法性正则表达式
else:
ereg = re.compile(
'[1-9][0-9]{5}(19[0-9]{2}|20[0-9]{2})((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}[0-9Xx]$') # //平年出生日期的合法性正则表达式
# //测试出生日期的合法性
if (re.match(ereg, idcard)):
# //计算校验位
S = (int(idcard_list[0]) + int(idcard_list[10])) * 7 + (int(idcard_list[1]) + int(idcard_list[11])) * 9 + (
int(
idcard_list[2]) + int(idcard_list[12])) * 10 + (
int(idcard_list[3]) + int(idcard_list[13])) * 5 + (int(
idcard_list[4]) + int(idcard_list[14])) * 8 + (int(idcard_list[5]) + int(idcard_list[15])) * 4 + (int(
idcard_list[6]) + int(idcard_list[16])) * 2 + int(idcard_list[7]) * 1 + int(idcard_list[8]) * 6 + int(
idcard_list[9]) * 3
Y = S % 11
M = "F"
JYM = "10X98765432"
M = JYM[Y] # 判断校验位
if (M == idcard_list[17]): # 检测ID的校验位
return Errors[0]
else:
return Errors[3]
else:
return Errors[2]
else:
return Errors[1]
re模块常用函数
complie()
'''
re.compile(patten,flags=0)
参数一:正则表达式
参数二:标志位re.M
功能:返回一个编译正则的对象
优点:
提高效率,对于常用的一些正则我们将其编译为对象,需要正则的的时候,调用此对象即可
'''
com = re.compile("^134\d{8}")
print(com.findall("1234345566676"))
print(com.findall("13455666761"))
match()
'''
re.match(patten,string,flags=0)
功能:只在字符串开始的位置进行匹配,匹配成功的返回一个匹配对象,匹配失败的时候返回None
注意:这个方法并不是完全匹配,若patten匹配到最后仍有剩余字符串,仍然视为匹配成功
若想完全匹配可以在表达式的结尾添加”$“.
'''
print(re.match("134\d{8}$","1345566677711"))
print(re.match("134\d{8}","1345566677711"))
search()函数
'''
re.search(patten,string,flags=0)
功能:匹配整个字符串,返回第一个匹配结果【匹配对象】
若找不到就返回None。
'''
print(re.search(r"\bgood\b","you are a good good man").group())
findall()
'''
re.findall(patten,string,flags=0)
功能:遍历匹配,匹配整个字符串,返回所有的匹配结果【列表】.
当匹配失败的时候,返回一个空的列表。
'''
print(re.findall("good","you are a goods good man"))
p = re.compile(r"\d+")
print(p.findall('o1n2m3k4'))
sub()
'''
re.sub(patten,repl,string,count,flags)
替换string中每一个匹配的子串后返回替换后的【新字符串】。
参数一:要匹配的字符串【旧串】
参数二:替换的字符串 【新串】
参数三:传入的字符串
参数四:指定替换的次数【若不指定则默认为0,全部替换】
参数五:标志位
'''
print(re.sub("\d+","\t","hello122hello222hello11113",count=2))
print(re.sub("\d+","\t","hello122hello222hello11113"))
text = "Bob is a handsome boy, he is cool, clever, and so on..."
print(re.sub(r'\s+', '-', text))
split()
'''
re.split(patten,string[,maxsplit])
功能:以指定的匹配正则的字符串来进行切片,返回一个【列表】
注意:当maxsplit不指定的时候,默认整个字符串全部切片。
'''
print(re.split("\d+","hello122hello222hello11113",maxsplit=2))
正则表达式修饰符 - 可选标志
正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:
修饰符 | 描述 |
---|---|
re.I | 使匹配对大小写不敏感 |
re.L | 做本地化识别(locale-aware)匹配 |
re.M | 多行匹配,影响 ^ 和 $ |
re.S | 使 . 匹配包括换行在内的所有字符 |
re.U | 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. |
re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 |