zoukankan      html  css  js  c++  java
  • python基础之坑爹正则表达式

    python基础之坑爹正则表达式

    概述

    re模块就是python语言中的正则表达式,拆出来单独写一条blog是因为正则表达式本身就是比较庞大的知识,写具体些让自己以后方便查找。

    IP:
    ^(25[0-5]|2[0-4]d|[0-1]?d?d)(.(25[0-5]|2[0-4]d|[0-1]?d?d)){3}$
    手机号:
    ^1[3|4|5|8][0-9]d{8}$
    

    由于在python中,“”也被定义为转义字符,因此两个python中的“”才能代表一个正则中的“”,这就导致了大量的“”重复。为了解决这一问题,python提供了原生字符的办法。也就是在字符串前面加上一个“r”,代表此字符串中的“”可直接用于正则表达式,而不用再次转义。因此,请养成在python的正则表达式字符串的前面添加一个“r“的好习惯。

    字符

    字符匹配分为普通字符和元字符.

    • 大多数字符都会和自身匹配
    • 元字符,元字符在[]中没有特殊意义,元字符包括:
    元字符 含义
    . 匹配除换行符外的所有字符
    w 匹配字母或者数字或者下划线或汉字
    W 匹配任何非字母或数字或下划线,汉字
    s 匹配任意的空白符,相当于[ fv]
    S 匹配任意非空白字符
    d 匹配任意十进制数字
    D 匹配任意非数字字符
     匹配单词的开始或者结束,即单词和空格的位置,只是匹配字符串开头结尾及空格回车等的位置, 不会匹配空格符本身
    ^ 匹配字符串的开始
    匹配字符串的结束
    * 重复0次或更多次
    + 重复1次或多次
    ? 重复0次或1次
    {n} 重复n次
    {n,} 重复n次或更多次
    {n,m} 重复n到m次
    [] 用来指定一个字符集和范围,字符可以单个列出,也可以用“-”号分隔的两个给定.字符来表示一个字符区间。例如,[abc] 将匹配"a", "b", 或 "c"中的任意一个字符;也可以用区间[a-c]来表示同一字符集,和前者效果一致
    反斜杠跟后面的元字符,去除元字符的特殊功能;与普通字符一起,实现特殊功能.
    () 分组功能

    字符中需要注意的事项

    • 如果元字符存在于[]中的字符类中时,只有字符^,-,有特殊含义.其他无特殊意义.例如:

    例如,[akm(]将匹配字符"a", "k", "m", 或 ")" 中的任意一个;"$"通常用作元字符,但在字符类别里,其特性被除去,恢复成普通字符。

    元字符 含义
    仍表示转义
    - 表示范围
    ^ ^放在支付前面,表示非
    • *?,+?,??,{m,n}? 前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配,后面加个问号,将策略改为非贪婪,只匹配尽量少的RE,来个例子吧:
    >>> re.findall(r"a(d+?)","a23b") # 非贪婪模式
            ['2']
    >>> re.findall(r"a(d+)","a23b")
            ['23']
    
    •  就是用在你匹配整个单词的时候。 如果不是整个单词就不匹配。 你想匹
      配 I 的话,你知道,很多单词里都有I的,但我只想匹配I,就是“我”,这个时
      候用 I

    re模块中的函数

    函数 描述 返回值
    compile(pattern[, flags]) 根据包含正则表达式的字符串创建模式对象 re模块的对象
    search(pattern, string[, flags]) 在字符串中寻找模式 第一个匹配到或者None
    match(pattern, string[, flags]) 在字符串的开始处匹配模式 在字符串开头匹配的对象或者None
    split(pattern, string[, maxsplit=0,flags]) 根据模式的匹配项来分割字符串 分割后的字符串列表
    findall(pattern, string,flags) 列出字符串中模式的所有匹配项 所有匹配到的字符串列表
    sub(pat,repl, string[,count=0,flags]) 将字符串中所有的pat的匹配项用repl替换 完成替换后的新字符串
    finditer(pattern, string,flags) 将所有匹配到的项生成一个迭代器 所有匹配到的字符串组成的迭代器
    subn(pat,repl, string[,count=0,flags]) 在替换字符串后,同时报告替换的次数 完成替换后的新字符串以及替换的次数,返回值为元组数据
    escape(string) 将字符串中所有特殊正则表达式字符串转义 转义后的字符串
    purge(pattern) 清空正则表达式
    template(pattern[,flags]) 编译一个匹配模板 模式对象
    fullmatch(pattern, string[, flags]) match函数的全字符串匹配版本 类似match的返回值

    compile

    将正则表达式转换为模式对象,提高工作效率。使用compile转换后,以后在每次模式使用时直接调用即可!经过compile转换的正则也能使用普通的re函数。

    import re
    res=re.compile(r'abc')
    print(res.match('abcde'))
    print(res.match('abcd123').group)
    print(res.match('abcd123').group())
    

    输出:

    <_sre.SRE_Match object; span=(0, 3), match='abc'>
    <built-in method group of _sre.SRE_Match object at 0x0000016911B395E0>
    abc
    

    从输出的结果我们可以看出来,compile处理后,返回的是re对象。事实上,compile是在调用match,findall函数之前默认优先编译的一步,所有我们可以在重复调用的某匹配的时候,可先将re.compile赋值于一个变量。

    match

    match对指定字符串的开头进行匹配,匹配成功后返回一个match的object,如果匹配不成功返回None!

    res=re.match(r'abc','123')
    print(res)
    res1=re.match(r'abc','abc23')
    print(res1)
    print(res1.start())
    print(res1.end())
    print(res1.span())
    print(res1.group())
    

    out:

    None
    <_sre.SRE_Match object; span=(0, 3), match='abc'>
    0
    3
    (0, 3)
    abc
    
    

    out中span表示匹配到数字的下标范围,从0到2,所以与列表、字典中取值是相同的
    group()是用来直接查看匹配的结果的

    search用来在指定字符串中查找,返回值为第一个匹配到的字符串
    使用方法和match类似

    res=re.search(r'abc','123abcsdfsdfsdfabc')
    print(res.group())
    print(res.start())
    print(res.end())
    print(res.span())
    

    结果:

    abc
    3
    6
    (3, 6)
    

    findall

    findall是搜索指定字符串中的所有指定匹配项,返回值为一个列表,如果没有匹配项,那么返回的是一个空列表,而且,findall不需要group()

    res=re.findall(r'efg','12efg,sdf,efgsdfsd')
    print(res)
    res1=re.findall(r'efg','12asdfasdfasdf')
    print(res1)
    

    out:

    ['efg', 'efg']
    []
    

    split

    split类似字符串中的分割,用来指定字符串为分隔符,将匹配目标分割成列表形式。而且split有一个maxsplit的参数,用来指定分割的次数

    s='1*8+2-6*-10'
    res=re.split(r'[+-*/]',s)
    print(res)
    res1=re.split(r'[+-*/]',s,maxsplit=3)
    print(res1)
    

    out:

    ['1', '8', '2', '6', '', '10'] #1
    ['1', '8', '2', '6*-10']
    

    注意看结果,#1标志中,为什么第一行的结果,索引-2会是一个空值呢,,是因为"6*-10",将*切割,10前面的负号和星号中间为空值

    而利用re模块中牛逼哄哄的分组功能,能将分割出来的字符串包括分隔符都加入列表中。来看下:

    s='1*8+2-6*-10'
    res2=re.split(r'([+-*/])',s)
    print(res2)
    

    out:

    ['1', '*', '8', '+', '2', '-', '6', '*', '', '-', '10']
    

    sub

    sub类似字符串中的replace功能,用指定的内容替换匹配到的字符或字符串,同时也可以指定替换次数,使用count= 来指定,或者直接数字也可

    s='hello,I am cc!What the fuck day!'
    res=re.sub(r'a','xxx',s)
    print(res)
    res2=re.sub(r'a','xxx',s,count=2)
    print(res2)
    

    out:

    hello,I xxxm cc!Whxxxt the fuck dxxxy!
    hello,I xxxm cc!Whxxxt the fuck day!
    

    subn

    看代码吧,同上,只不过比sub多了替换次数,返回值为元组

    s='hello,I am cc!What the fuck day!'
    res=re.subn(r'a','xxx',s)
    print(res)
    print(type(res))
    

    out:

    ('hello,I xxxm cc!Whxxxt the fuck dxxxy!', 3)
    <class 'tuple'>
    

    group和groups

    groups返回元组,group返回的是字符串
    直接看代码吧:

    a = "123abc456"
    print(re.search(r"([0-9]*)([a-z]*)([0-9]*)", a).groups())
    print(re.search(r"([0-9]*)([a-z]*)([0-9]*)", a).group())
    print(re.search(r"([0-9]*)([a-z]*)([0-9]*)", a).group(0))
    print(re.search(r"([0-9]*)([a-z]*)([0-9]*)", a).group(1))
    print(re.search(r"([0-9]*)([a-z]*)([0-9]*)", a).group(2))
    print(re.search(r"([0-9]*)([a-z]*)([0-9]*)", a).group(3))
    

    out:

    ('123', 'abc', '456')
    123abc456
    123abc456
    123
    abc
    456
    

    flag编译标识

    flag为re匹配时的匹配模式,有X I M S A L U,7种模式.

    标识符 全拼 作用
    I IGNORECASE 忽略大小写
    L LOCALE 使w, W, , B, d, D依赖于本地设置
    M MULTILINE 让正则表达式的^和$符号可以适应多行模式的字符串
    X VERBOSE 注释模式
    A ASCII 对于字符串,使得w, W, , B, d, D只匹配ACSII码字符集,而不是整个Unicode字符集(默认);对于bytes模式,这个编译标志是默认设置,不需要特别指定。
    S DOTALL 使 "." 特殊字符完全匹配任何字符,包括换行;没有这个标志, "." 匹配除了换行外的任何字符
    U UNICODE 兼容模式。在字符串模式下被忽略(默认模式),在字节模式下被禁止

    M说明下:

    s='
    123
    '
    res=re.search(r'^123',s)
    print(res.group())
    

    这么执行会报错.
    但如果使用下面re.M就会正常:

    res1=re.search(r'^123',s,re.M)
    print(res1.group())
    

    分组

    先上例子:

    >>> p = re.compile('(a(b)c)d')
    >>> m = p.match('abcd')
    >>> m.group(0)
    'abcd'
    >>> m.group(1)
    'abc'
    >>> m.group(2)
    'b'
    

    分组是在re中比较牛逼的东西,功能:去已经匹配到的结果中再提取数据,相当于二次过滤.
    提取分组结果使用group groups groupdict

    先来看下无分组的结果:

    s='abc23434efdabceab'
    res=re.match(r'aw+',s)
    print(res.group())
    print(res.groups())
    print(res.groupdict())
    

    out:

    
    abc23434efdabceab
    ()
    {}
    

    再来看有分组的:

    s='abc23434efdabceab2'
    res=re.match(r'a(w+).*(?P<name>d)$',s)
    print(res.group())
    print(res.groups())
    print(res.groupdict())
    

    out:

    abc23434efdabceab2
    ('bc23434efdabceab', '2')
    {'name': '2'}
    

    解释下:匹配时是按r''中的整体去匹配的,第一次匹配完之后,然后再用括号去匹配.有两个括号,那就是从匹配到的结果中,再过滤出两个匹配的结果.再看个例子:

    
    s='abc23434efdabceab2'
    res=re.search(r'a(w+).*(?P<name>d)$',s)
    print(res)
    print(res.group())
    print(res.group(0))
    print(res.group(1))
    print(res.group(2))
    print(res.groups())
    print(res.groupdict())
    

    out:

    <_sre.SRE_Match object; span=(0, 18), match='abc23434efdabceab2'>
    abc23434efdabceab2
    abc23434efdabceab2
    bc23434efdabceab
    2
    ('bc23434efdabceab', '2')
    {'name': '2'}
    

    可以看出来,group 结果的字符串,groups是元组,groupdict是字典.在group结果中,获取分组结果时,取括号的索引即可,第几个就是group(几),group(0)是第一次匹配出的结果本身

    findall,split中的分组有歧义

    origin = "hello alex bcd alex lge alex acd 19"
    r = re.split("a(le)x", origin)
    print(r)
    

    out:

    ['hello ', 'le', ' bcd ', 'le', ' lge ', 'le', ' acd 19']
    
    s='abc1223434efdabc34121224eabc12'
    res=re.findall(r'a(bc)(12)*',s)
    print(res)
    

    out:

    [('bc', '12'), ('bc', ''), ('bc', '12')]
    

    sub中没有分组的概念

    s='abc1223434efdabc34121224eabc12'
    res=re.sub(r'a(bc)(12)*','xxx',s)
    print(res)
    

    out:

    xxx23434efdxxx34121224exxx
    

    看来并没有什么乱用!

  • 相关阅读:
    ORA-22835:缓冲区对于CLOB到CHAR转换而言太小
    C#发起Http请求,调用接口
    C#发起HTTP请求Post请求
    C# 调用HTTP接口两种方式Demo WebRequest/WebResponse 和WebApi
    SQL中的子查询
    C# 使用multipart form-data方式post数据到服务器
    批处理框架 Spring Batch 这么强,你会用吗
    JAVA基础(一)
    数据库---连接查询多表查询
    数据库---约束
  • 原文地址:https://www.cnblogs.com/ccorz/p/5585017.html
Copyright © 2011-2022 走看看