47-re模块

作者: ju7ran | 来源:发表于2019-05-04 13:33 被阅读3次

    re模块

    在Python中,通过内置的re模块提供对正则表达式的支持。正则表达式会被编译成一系列的字节码,然后由通过C编写的正则表达式引擎进行执行。该引擎自从Python1.6被内置以来,近20年时间未有发生过变化

    re模块支持下面的正则语法:

    "."      
    "^"      
    "$" 
    "*"     
    "+"      
    "?"      
    *?,+?,?? 
    {m,n}    
    {m,n}?   
    "\\"     
    []      
    "|"      
    (...)    
    (?aiLmsux)
    (?:...)  
    (?P<name>...) 
    (?P=name)     
    (?#...)  
    (?=...) 
    (?!...) 
    (?<=...) 
    (?<!...) 
    (?(id/name)yes|no)
    

    提供了下面的方法进行字符串的查找、替换和分割等各种处理操作

    方法 描述 返回值
    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的返回值

    反斜杠的困扰:\

    与大多数编程语言相同,正则表达式里使用\作为转义字符,这可能造成反斜杠困扰。假如需要匹配文本中的字符\,那么使用编程语言表示的正则表达式里将需要4个反斜杠\\\\。前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。为了方便我们使用个,Python提供了原生字符串的功能,很好地解决了这个问题,这个例子中的正则表达式可以使用r"\\"表示。同样,匹配一个数字的"\\d"可以直接写成r"\d"。有了原生字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。

    compile(pattern, flags=0)

    这个方法是re模块的工厂方法,用于将字符串形式的正则表达式编译为Pattern模式对象,可以实现更高效率的匹配。第二个参数flag是匹配模式。

    使用compile()完成一次转换后,再次使用该匹配模式的时候就不用进行转换了。经过compile()转换的正则表达式对象也能使用普通的re方法。其用法如下:

    import re
    pat = re.compile(r"abc")
    pat.match("abc123")
    <_sre.SRE_Match object; span=(0, 3), match='abc'>
    

    经过compile()方法编译过后的返回值是个re对象,它可以调用match()、search()、findall()等其他方法,但其他方法不能调用compile()方法。实际上,match()和search()等方法在使用前,Python内部帮你进行了compile的步骤。

    re.match(r"abc","abc123").compile()
    Traceback (most recent call last):
      File "<pyshell#7>", line 1, in <module>
        re.match(r"abc","abc123").compile()
    AttributeError: '_sre.SRE_Match' object has no attribute 'compile'
    

    match(pattern, string, flags=0)

    match()方法会在给定字符串的开头进行匹配,如果匹配不成功则返回None,匹配成功返回一个匹配对象,这个对象有个group()方法,可以将匹配到的字符串给出。

    ret = re.match(r"abc","ab1c123")
    print(ret)
    None
    re.match(r"abc","abc123")
    <_sre.SRE_Match object; span=(0, 3), match='abc'>
    obj = re.match(r"abc","abc123")
    obj.group()
    'abc'
    

    search(pattern, string, flags=0)

    在文本内查找,返回第一个匹配到的字符串。它的返回值类型和使用方法与match()是一样的,唯一的区别就是查找的位置不用固定在文本的开头。

    obj = re.search(r"abc","123abc456abc789")
    obj
    <_sre.SRE_Match object; span=(3, 6), match='abc'>
    obj.group()
    'abc'
    obj.start()
    3
    obj.end()
    6
    obj.span()
    (3, 6)
    

    findall(pattern, string, flags=0)

    作为re模块的三大搜索函数之一,findall()和match()、search()的不同之处在于,前两者都是单值匹配,找到一个就忽略后面,直接返回不再查找了。而findall是全文查找,它的返回值是一个匹配到的字符串的列表。这个列表没有group()方法,没有start、end、span,更不是一个匹配对象,仅仅是个列表!如果一项都没有匹配到那么返回一个空列表。

    obj = re.findall(r"abc","123abc456abc789")
    obj
    ['abc', 'abc']
    obj.group()
    Traceback (most recent call last):
      File "<pyshell#37>", line 1, in <module>
        obj.group()
    AttributeError: 'list' object has no attribute 'group'
    obj = re.findall(r"ABC","123abc456abc789")
    print(obj)
    []
    

    split(pattern, string, maxsplit=0, flags=0)

    re模块的split()方法和字符串的split()方法很相似,都是利用特定的字符去分割字符串。但是re模块的split()可以使用正则表达式,因此更灵活,更强大,而且还有“杀手锏” 。

    s = "8+7*5+6/3"
    import re
    a_list = re.split(r"[\+\-\*\/]",s)
    a_list
    ['8', '7', '5', '6', '3']
    

    split有个参数maxsplit,用于指定分割的次数:

    a_list = re.split(r"[\+\-\*\/]",s,maxsplit= 2)
    a_list
    ['8', '7', '5+6/3']
    

    sub(pattern, repl, string, count=0, flags=0)

    sub()方法类似字符串的replace()方法,用指定的内容替换匹配到的字符,可以指定替换次数。

    s = "i am jack! i am nine years old ! i like swiming!"
    import re
    s = re.sub(r"i","I",s)
    s
    'I am jack! I am nIne years old ! I lIke swImIng!'
    

    分组功能

    Python的re模块有一个分组功能。所谓的分组就是去已经匹配到的内容里面再筛选出需要的内容,相当于二次过滤。实现分组靠圆括号(),而获取分组的内容靠的是group()、groups()和groupdict()方法,其实前面我们已经展示过。re模块里的几个重要方法在分组上,有不同的表现形式,需要区别对待。

    例一:match()方法,不分组时的情况:

    import re
    origin = "hasdfi123123safd"
    # 不分组时的情况
    r = re.match("h\w+", origin)
    print(r.group())         # 获取匹配到的整体结果
    print(r.groups())        # 获取模型中匹配到的分组结果元组
    print(r.groupdict())     # 获取模型中匹配到的分组中所有key的字典
    
    结果:
    hasdfi123123safd
    ()
    {}
    

    例二:match()方法,有分组的情况(注意圆括号!)

    import re
    origin = "hasdfi123123safd123"
    # 有分组
    r = re.match("h(\w+).*(?P<name>\d)$", origin)
    print(r.group())  # 获取匹配到的整体结果
    print(r.group(1))  # 获取匹配到的分组1的结果
    print(r.group(2))  # 获取匹配到的分组2的结果
    print(r.groups())  # 获取模型中匹配到的分组结果元组
    print(r.groupdict())  # 获取模型中匹配到的分组中所有key的字典
    
    执行结果:
    hasdfi123123safd123
    asdfi123123safd12
    3
    ('asdfi123123safd12', '3')
    {'name': '3'}
    

    例三,search()方法,有分组的情况:

    import re
    origin = "sdfi1ha23123safd123"      # 注意这里对匹配对象做了下调整
    # 有分组
    r = re.search("h(\w+).*(?P<name>\d)$", origin)
    print(r.group())  
    print(r.group(0))  
    print(r.group(1))  
    print(r.group(2))
    print(r.groups())  
    print(r.groupdict()) 
    
    执行结果:
    ha23123safd123
    ha23123safd123
    a23123safd12
    3
    ('a23123safd12', '3')
    {'name': '3'}
    

    例四,findall()方法,没有分组的情况:

    import re
    origin = "has something have do"
    # 无分组
    r = re.findall("h\w+", origin)
    print(r)
    
    执行结果:
    ['has', 'hing', 'have']
    # 一切看起来没什么不一样
    

    例五,findall()方法,有一个分组的情况:

    import re
    origin = "has something have do"
    # 一个分组
    r = re.findall("h(\w+)", origin)
    print(r)
    
    执行结果:
    ['as', 'ing', 'ave']
    

    例六,findall()方法,有两个以上分组的情况:

    import re
    origin = "hasabcd something haveabcd do"    # 字符串调整了一下
    # 两个分组
    r = re.findall("h(\w+)a(bc)d", origin)
    print(r)
    
    运行结果:
    [('as', 'bc'), ('ave', 'bc')]
    

    如何拆分含有多种分隔符的字符串

    我们要把某字符串依据分隔符号拆分不同的字段,该字符串包含多种不同的分隔符,例如:
    s = 'ab;cd|efg|hi|hi,jkl\topq;str,ubw\asyd'
    其中<,>,<;>,<|>,<\t> 都是分隔符号,如何处理?

    第一种方法,可以连续使用str.split()方法,每次处理一种分割符号

    def mySplit(s,ds):
        res = [s]
        for d in ds:
            t = []
            list(map(lambda x:t.extend(x.split(d)),res))
            res = t
        return res
    s = 'ab;cd|efg|hi|hi,jkl\topq;str,ubw\x07syd'
    print(mySplit(s,',;|\t'))
    
    如果出现连续的分割符号,会出现空字符的情况,这时候如果我们想去掉空字符串。
    return [x for x in res if x]
    用列表推导式可以完成这个需求。
    

    第二种方法,使用正则表达式的re.split()方法,一次性拆分字符串

    import re
    re.split(r'[,;\t|]+',s)
    
    

    某软件要求,从网络抓取各个城市气温信息,并依次显示
    北京:15-17
    天津:17-22
    长春:12-18
    如果一次抓取所有城市天气再显示,显示第一个城市气温时,有很高的延迟,并且浪费存储空间,我们期望以用时访问的策略,并且能把所有城市气温封装到一个对象里,可用for语句进行迭代,如何解决?

    import requests
    
    def getWeather(city):
        r = requests.get('http://wthrcdn.etouch.cn/weather_mini?city='+city)
        data = r.json()['data']['forecast'][0]
        return '%s:%s,%s'%(city,data['low'],data['high'])
    
    print(getWeather('北京'))
    

    如何调整字符串中文本的格式

    日期格式为'yyyy-mm-dd':

    image.png

    我们想把其中日期改为美国日期的格式'mm/dd/yyyy'
    '2016-05-23'=>'05/23/2016',应该如何处理?

    import re
    re.sub('(\d{4})-(\d{2})-(\d{2})',r'\2/\3/\1',file)
    
    re.sub('(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})',r'\g<month>/\g<day>/\g<year>',file)
    

    相关文章

      网友评论

        本文标题:47-re模块

        本文链接:https://www.haomeiwen.com/subject/ituxoqtx.html