正则表达式-python向

正则表达式

正则的元字符

w3c的零基础教程:https://www.w3cschool.cn/regexp/zoxa1pq7.html

正则表达式30分钟入门教程:http://deerchao.net/tutorials/regex/regex.htm

微软的正则表达式https://docs.microsoft.com/zh-cn/dotnet/standard/base-types/regular-expression-language-quick-reference

正则速查: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 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容

  • 正则表达式到底是什么东西?字符是计算机软件处理文字时最基本的单位,可能是字母,数字,标点符号,空格,换行符,汉字等...
    狮子挽歌阅读 2,134评论 0 9
  • 原文:http://www.jb51.net/tools/zhengze.html 然后强迫症如我,因为我怕网页哪...
    你再不来我要下雪了阅读 833评论 1 6
  • 注:本篇文章只为方便查看,特此保留,如有冒犯,敬请谅解!!! 本文目标 30分钟内让你明白正则表达式是什么,并对它...
    阿杰Alex阅读 1,475评论 0 10
  • 版本:v2.3.5 (2017-6-12) 作者:deerchao 转载请注明来源 目录 跳过目录 本文目标 如何...
    readilen阅读 945评论 2 13
  • 之前看过的关于正则的一篇优秀文章,今儿上午没事,摘录给大家复习、分享放下微信,耐心读完相信我,你会有所收获的 本文...
    simuty阅读 1,090评论 0 1