• Python之正则表达式



    引入

    字符串是一种很重要的数据类型。很多程序都需要在一大串字符中查找满足特定规则的子串。(如匹配电话号码、邮箱等)

    简而言之,正则表达式是记录文本规则的字符串代码。

    我们当然可以自己通过复杂的算法写出一个个字符串匹配函数,但其实在实际开发过程中并没有这个必要。因为前人已经为我们做了这个工作。他们发明了正则表达式(regular expression)。

    正则表达式描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。

    很多编程语言都对正则表达式进行了实现。Python也不例外。有关正则表达式的函数在都在re模块中。

    import re
    
    str_to_operate="要进行匹配的长字符串"
    
    #通过模式字符串得到一个pattern对象regex
    regex=re.compile(r"模式字符串")    #r代表纯字符串,即不支持转义字符的字符串
    
    #用regex去str_to_operate中匹配子串
    #如果匹配到,返回一个match对象mo(match_object简称)
    #如果没有匹配到,返回None
    mo=regex.search(str_to_operate)
    
    #通过mo的group()方法
    #获取匹配到的子串
    result=mo.group()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    匹配单个字符

    字母数字自己对自己

    我们当然可以用某个字符(字母、数字)来匹配它本身。

    如:

    str_to_operate="1234567890abcd"
    regex=re.compile(r"90ab")    
    mo=regex.search(str_to_operate)
    print(mo.group())
    #90ab
    
    • 1
    • 2
    • 3
    • 4
    • 5

    字符类型

    我们可以通过字符类型来匹配单个字符

    字符分类/代码含义助记
    \d0-9中任意一个数字decimal
    \D除0-9的数字外的任意一个字符
    \w任意一个字母、数字,或下划线word
    \W除字母、数字,或下划线以外的任意一个字符
    \s一个空格、tab、或换行符space
    \S除空格、tab、或换行符外的任意一个字符
    .通配符,默认可以匹配除换行符外的任意字符

    如:

    str_to_operate="姓名:张三\n联系方式:15070997464\n家庭住址:警局"
    regex=re.compile(r"\w\w\w\w:\d\d\d\d\d\d\d\d\d\d\d")    
    mo=regex.search(str_to_operate)
    print(mo.group())
    #联系方式:15070997464
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ()分组匹配

    我们需要匹配的子串,通常由几部分含有各种含义的字符组成。如,需要匹配出生日期,它就由年、月、天组成。

    我们可以在模式字符串中用()标识分组。再用mo对象的group()通过索引获取对应组中的子串。

    如:

    import re
    
    str_to_operate="姓名:张三"
    regex=re.compile(r"(姓名):(张三)")    
    mo=regex.search(str_to_operate)
    print(mo.group(0))
    #姓名:张三
    print(mo.group(1))
    #姓名
    print(mo.group(2))
    #张三
    print(mo.groups())
    #('姓名', '张三')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 可以发现,group(0)能够获取匹配的整个子串。实际上,group()不填参数的话,默认传0
    • group(1)代表第1个小括号分组中的内容
    • group(2)代表第2个小括号分组中的内容
    • groups()以有序元组的形式,返回所有分组中的内容

    正则表达式中的转义字符

    r"字符串"会让字符串不支持转义字符,这里的转义字符是普通意义上的,如\n换行

    但是,在正则表达式中,也有很多特殊字符,比如这里的().

    事实上,尽管有r,但compile()函数会支持正则表达式中的转义字符

    .    ^   $    *   +   ?  {   }   [   ]   \   |   (   )
    \.  \^  \$  \*   \+  \? \{  \}  \[  \]  \\  \|  \(  \)
    
    • 1
    • 2

    |多模式匹配

    我们需要匹配的字符串模式,通常不是一成不变的。同种含义的字符,可能有多种模式。如匹配张三以及他的电话号码,张三可能还有小名:小三,张小三等。

    我们可以在模式字符串中用管道符|标识多种匹配模式。只要满足其一,就可被匹配。

    如:

    import re
    
    str_to_operate1="aaaaa张三:11011011011bbbbb"
    str_to_operate2="aaaaa小三:12012012011bbbbb"
    str_to_operate3="aaaaa张小三:13013013011bbbbb"
    regex=re.compile(r"(张小三|小三|张小三):(\d\d\d\d\d\d\d\d\d\d\d)")    
    mo1=regex.search(str_to_operate1)
    print(mo1.groups())
    #('张三', '11011011011')
    mo2=regex.search(str_to_operate2)
    print(mo2.groups())
    #('小三', '12012012011')
    mo3=regex.search(str_to_operate3)
    print(mo3.groups())
    #('张小三', '13013013011')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    ?可选匹配

    我们需要匹配的字符串模式,可能有些字符是允许有,也允许没有的。如匹配身份信息,配偶一项就可能没有。

    我们可以使用?来让它前面的字符或者分组变成可选的。即,有没有都可以匹配。

    如:

    str_to_operate1 = "aaaaa姓名:张三 配偶:李四 年龄:30bbbbb"
    str_to_operate2 = "aaaaa姓名:王五 年龄:40bbbbb"
    regex = re.compile(r"姓名:\w\w\w?\s(配偶:\w\w\w?\s)?年龄:\d\d\d?")
    mo1 = regex.search(str_to_operate1)
    print(mo1.group())
    #姓名:张三 配偶:李四 年龄:30
    mo2 = regex.search(str_to_operate2)
    print(mo2.group())
    #姓名:王五 年龄:40
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    多次匹配

    用*匹配零次或多次

    *前面的字符或分组出现零次或者多次,都能匹配上。

    str_to_operate1="hellooooooooooooooooo!"
    str_to_operate2="hello!"
    str_to_operate3="hell!"
    regex=re.compile(r"hello*")    
    mo1=regex.search(str_to_operate1)
    print(mo1.group())
    #hellooooooooooooooooo
    mo2=regex.search(str_to_operate2)
    print(mo2.group())
    #hello
    mo3=regex.search(str_to_operate3)
    print(mo3.group())
    #hell
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    +匹配一次或多次

    str_to_operate1="hellooooooooooooooooo!"
    str_to_operate2="hello!"
    str_to_operate3="hell!"
    regex=re.compile(r"hello+")    
    mo1=regex.search(str_to_operate1)
    print(mo1.group())
    #hellooooooooooooooooo
    mo2=regex.search(str_to_operate2)
    print(mo2.group())
    #hello
    mo3=regex.search(str_to_operate3)
    print(mo3.group())
    #None
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    {}匹配特定次数

    {m},只有前面的字符出现m次,才能匹配上

    {m,n},前面的字符出现m到n次(包含m,n次),才能匹配上

    贪心与非贪心

    {m,n}默认匹配能够匹配的最长子串。这称为贪心匹配。

    在{m,n}后加上?,即{m,n}?,可以变成非贪心匹配。即匹配能够匹配的最短子串。

    如:

    str_to_operate1="hellooooo!"
    str_to_operate2="hellooo!"
    str_to_operate3="hello!"
    
    #3次
    regex1=re.compile(r"hello{3}")    
    mo1=regex1.search(str_to_operate1)
    print(mo1.group())
    #hellooo
    mo2=regex1.search(str_to_operate2)
    print(mo2.group())
    #hellooo
    mo3=regex1.search(str_to_operate3)
    print(mo3)
    #None
    
    #贪心2到5次
    regex2=re.compile(r"hello{2,5}")    
    mo4=regex2.search(str_to_operate1)
    print(mo4.group())
    #hellooooo
    mo5=regex2.search(str_to_operate2)
    print(mo5.group())
    #hellooo
    mo6=regex2.search(str_to_operate3)
    print(mo6)
    #None
    
    #非贪心2到5次
    regex3=re.compile(r"hello{2,5}?")    
    mo7=regex3.search(str_to_operate1)
    print(mo7.group())
    #helloo
    mo8=regex3.search(str_to_operate2)
    print(mo8.group())
    #helloo
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    findall()

    search只会匹配第一个能被匹配的子串,而findall能匹配所有能够被匹配的子串。并且直接返回由 子串的组组成的元组 组成的列表

    str_to_operate="name='张三' age=18; name='李四' age=19;name='王五' age=20;"
    regex=re.compile(r"name='(\w\w)' age=(\d\d);")
    mo=regex.search(str_to_operate)
    print(mo.groups())
    #('张三', '18')
    result=regex.findall(str_to_operate)
    print(result)
    #[('张三', '18'), ('李四', '19'), ('王五', '20')]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    用[]组合匹配

    []中的字符都能匹配。

    如[abc123]能够匹配abc123中的任意一个字符

    如果是连续的字母或者连续的数字,还可以用[a--z][A-Z]、``[0-9]`这种简写形式

    如:

    str_to_operate="第一名:张三;第2名:李四;第三名:王五;第4名:赵六;"
    regex=re.compile(r"第([1-3一二三])名:(\w\w)")
    result=regex.findall(str_to_operate)
    print(result)
    #[('一', '张三'), ('2', '李四'), ('三', '王五')]
    
    • 1
    • 2
    • 3
    • 4
    • 5

    用^排除匹配

    []中开头加一个^,就代表只要有[]中的字符就不能匹配,除此之外的其他字符都能匹配。


    sub()

    pattern对象的sub方法可以用来替换匹配到的子串。

    str_to_operate="......"
    regex=re.compile(r"模式字符串")
    result=regex.sub(new_str,str_to_operate)
    
    • 1
    • 2
    • 3

    在new_str中,还可以加上\group_num来使用匹配到的指定分组中的字符串

    如:

    str_to_operate="name:Zhang San"
    regex=re.compile(r"(name):(.+)")
    result=regex.sub(r"NAME:Mr.\2.",str_to_operate)
    print(result)
    #NAME:Mr.Zhang San.
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ^$定位匹配

    ^ 表示,只有以regex模式开头,才能被匹配。放在regex模式开头。

    $表示,只有以regex模式结束,才能被匹配。放在regex模式末尾。

    str_to_operate="hello,Jane.hello,Jack.Rose,hello"
    regex1=re.compile(r"^hello,(\w+).")
    regex2=re.compile(r"(\w+),hello$")
    mo1=regex1.search(str_to_operate)
    mo2=regex2.search(str_to_operate)
    print(mo1.groups())
    #('Jane',)
    print(mo2.groups())
    #('Rose',)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    模式flag

    在compile生成pattern对象时,可以传入一些flag参数

    regex=re.compile("匹配模式",flag1|flag2|...)
    
    • 1
    flag值含义
    re.VERBOSE忽略空白符和注释
    re.IGNORECASE忽略大小写
    re.DONALL让通配符可以匹配换行符

  • 相关阅读:
    Leetcode刷题——单链表2
    自动驾驶中的数据安全和隐私
    分类预测 | Matlab实现PSO-LSTM-Attention粒子群算法优化长短期记忆神经网络融合注意力机制多特征分类预测
    Ubuntu 生成ffmpeg安卓全平台so
    spring 事务源码剖析
    算法--排序算法效率比较
    2022年天猫8月份有什么大的活动?
    【打印机配置】斑马打印机配置步骤
    协同过滤推荐算法
    Pytorch里的manual_seed()
  • 原文地址:https://blog.csdn.net/ncu5509121083/article/details/125556844