zoukankan      html  css  js  c++  java
  • (十六)re模块

    正则表达式并不是Python的一部分,本质而言,正则表达式(或 RE)是一种小型的、高度专业化的编程语言。正则表达式是用于处理字符串的强大工具,很多编程语言都支持正则表达式的语法。

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

    普通字符:精确匹配

    >>> re.findall('nick','asdanickkyuj')
    ['nick']

    元字符:. ^ $ * + ? { } [ ] | ( )

    .    通配符,匹配任意除换行符" "外的一个字符

    >>> re.findall('n..k','asdanerkyuj')
    ['nerk']

    ^  以什么开头

    >>> re.findall('^n..k','asdanickkyuj')        #中间有nick是无法匹配的
    []
    >>> re.findall('^n..k','nickkyuj')            #必须是从头开始匹配
    ['nick']

    $  以什么结尾

    >>> re.findall('n..k$','nickkyuj')
    []
    >>> re.findall('n..k$','nickkyujnfdk')        #必须是从尾匹配
    ['nfdk']

    *  重复匹配上一个字符0到无穷大次

    +  重复匹配上一个字符1到无穷大次

    ?  重复匹配上一个字符0到1次

    >>> re.findall('yus*','nickkyusssss')           #s*匹配5个s
    ['yusssss']
    >>> re.findall('yus+','nickkyusssss')           #s+匹配5个s
    ['yusssss']
    >>> re.findall('yus*','nickkyu')                #s*匹配0个s
    ['yu']
    >>> re.findall('yus+','nickkyu')                #s+无法匹配
    []
    >>> re.findall('yus?','nickkyu')                #s?匹配0个s
    ['yu']
    >>> re.findall('yus?','nickkyusssss')           #s?匹配一个s
    ['yus']

    {}  重复匹配上一个字符自定义的次数

    {0,}相当于*  {1,}相当于+  {0,1}相当于?

    >>> re.findall('yus{0,6}','nickkyusssss')     #匹配0~6之间任意次数
    ['yusssss']
    >>> re.findall('yus{0,1}','nickkyusssss')     #相当于?  匹配一次
    ['yus']
    >>> re.findall('yus{6}','nickkyusssss')     #指定匹配6次,无法匹配
    []

    注意:前面的*,+,?等都是贪婪匹配,也就是尽可能多的匹配,后面加?号使其变成惰性匹配

    >>> re.findall('yus*','nickkyusssss')    #贪婪匹配
    ['yusssss']
    >>> re.findall('yus*?','nickkyusssss')   #惰性匹配
    ['yu']

    []  字符集,表示或的关系。在中括号里的字符,任选其一挨个匹配

    >>> re.findall('q[ab]','asdqaerqbsd')         #qa和qb挨个匹配
    ['qa', 'qb']
    >>> re.findall('q[a*]','asdqaaaerqbsd')       #qa和q*挨个匹配
    ['qa']
    >>> re.findall('q[.*+]','a.dqaaq+aerqbsd')    #q. q* q+挨个匹配
    ['q+']

    注意:在字符集[]里是没有元字符的概念的,. * + 这些仅仅就是字符

    除了这三个:-  ^ 

    -  表示范围,从xx到xx挨个匹配

    >>> re.findall('q[a-z]','a.dqaaq+aerqbsqqd')
    ['qa', 'qb', 'qq']
    >>> re.findall('q[a-z]*','a.dqaaqaerqbsqqd')  #[a-z]*匹配任意字母任意次
    ['qaaqaerqbsqqd']
    >>> re.findall('q[0-9]*','a.dqsd9')           #*匹配了0次,就匹配了一个q
    ['q']

    ^  注意这里是在[]里的^,不是上文描述的^,表示非

    >>> re.findall('q[^0-9]','a.dqsd9')
    ['qs']
    >>> re.findall('q[^a-z]','a.dqsd9')
    []

    需求:匹配 6+(3*7+2-(5-3))中的(5-3)     

    思路是:匹配括号开始,匹配括号结束,中间却又没有括号

    >>> re.findall('([^()]*)','6+(3*7+2-(5-3))')   #(和)是转义符表示()  [^()]*表示没有()的任意个字符
    ['(5-3)']

       转义符,后面详细说明

    >>> re.findall('[d]','123abc')
    ['1', '2', '3']

      转义符

    反斜杠后边跟元字符去除特殊功能,比如.
    反斜杠后边跟普通字符实现特殊功能,比如d

    加普通字符实现特殊功能:

    d  匹配任何十进制数;它相当于类 [0-9]。
    D 匹配任何非数字字符;它相当于类 [^0-9]。
    s  匹配任何空白字符;它相当于类 [ fv]。
    S 匹配任何非空白字符;它相当于类 [^ fv]。
    w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。
    W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]
      匹配一个特殊字符边界,比如空格 ,&,#等

    d与D :

    >>> re.findall('d','6+(31*7+23-(5-3))')     #匹配单个数字
    ['6', '3', '1', '7', '2', '3', '5', '3']
    >>> re.findall('d+','6+(31*7+23-(5-3))')    #匹配多个数字
    ['6', '31', '7', '23', '5', '3']
    >>> re.findall('D+','6+(31*7+23-(5-3))')    #匹配多个非数字
    ['+(', '*', '+', '-(', '-', '))']

    s与S :

    >>> re.findall('s','hello world!')
    [' ']
    >>> re.findall('S','hello world!')
    ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd', '!']

    w与W :

    >>> re.findall('w','hello_world!#')
    ['h', 'e', 'l', 'l', 'o', '_', 'w', 'o', 'r', 'l', 'd']
    >>> re.findall('W','hello_world!#')
    ['!', '#']

    :

    需求,要匹配 'hello I am LILY' 中的第一个I。思路是第一个I后面是空格,用

    >>> re.findall('I','hello I am LILY')
    []
    >>> re.findall(r'I','hello I am LILY')
    ['I']
    >>> re.findall('I\b','hello I am LILY')
    ['I']

    正则表达式re是一门独立的编程语言,在re中有特殊的意义(匹配一个特殊字符边界),然而,在Python中也有特殊的意义(不知道是啥),当Python解释器拿到,会转义为Python规定的那个特殊意义(不知道是啥),再丢给re,那re肯定不认识,所以无法匹配。

    第一种方法:r'I'

    r 代表的意思是: raw,raw string是原生字符串的意思。加上r表示里面的字符串不做任何转义,直接丢给re,所以r'I'的意思是Python解释器不做任何转义,将'I'交给re,re再去转义为I+一个特殊字符边界(这里是一个空格),成功匹配第一个I

    第二种方法:'I\b'

    Python解释器将'I\b'转义为'I'丢给re,re拿到'I',re再去转义为I+一个特殊字符边界(这里是一个空格),成功匹配第一个I

    同理:要匹配cm

    >>> re.findall('c\m','acms')
    []
    >>> re.findall(r'c\m','acms')
    ['c\m']
    >>> re.findall('c\\m','acms')
    ['c\m']

    要么r'c\m',Python不转义,re把c\m转义为cm,匹配成功

    要么'c\\m',Python转义为c\m,re把c\m转义为cm,匹配成功

    如上两个例子,使用转义符时,当Python里也有他自己的特殊转义规则时,要么直接加r让Python不做处理,要么处理好Python和re的两层转义。

    加元字符去除特殊功能:

    >>> re.findall('www.baidu','www.baidu')        #.是元字符,匹配'.',模糊匹配成功
    ['www.baidu']
    >>> re.findall('www.baidu','www.baidu')       #.是普通字符,匹配'.',精确匹配成功
    ['www.baidu']
    >>> re.findall('www*baidu','www*baidu')        #*是元字符,重复匹配前面的'w',无法匹配后面的'*'
    []
    >>> re.findall('www*baidu','www*baidu')       #*是普通字符,匹配'*',精确匹配成功
    ['www*baidu']

    |  表示或

    >>> re.findall('ca|fr','sca7fr89')             #ca或fr
    ['ca', 'fr']
    >>> re.findall('ca|d','sca7fr89')            #ca或数字
    ['ca', '7', '8', '9']
    >>> re.findall('ca|D','sca7fr89')             #ca或非数字
    ['s', 'ca', 'f', 'r']

    ()  分组

    >>> re.findall('abc+','abcccc')               #匹配c,1到无穷次
    ['abcccc']
    >>> re.findall('(abc)+','abcccc')             #abc作为一个整体去匹配,1到无穷次
    ['abc']

    命名分组

    >>> re.search('(?P<name>[a-z]+)(?P<age>d+)','nick20tom24jack28')                 #两个分组,name和age
    <_sre.SRE_Match object; span=(0, 6), match='nick20'>                              #search()方法只匹配第一个符合的结果,返回一个对象
    >>> re.search('(?P<name>[a-z]+)(?P<age>d+)','nick20tom24jack28').group()         #group()拿到匹配的结果
    'nick20'
    >>> re.search('(?P<name>[a-z]+)(?P<age>d+)','nick20tom24jack28').group('name')   #group('name')拿到第一个分组name的值nick
    'nick'
    >>> re.search('(?P<name>[a-z]+)(?P<age>d+)','nick20tom24jack28').group('age')
    '20'

    (?P<name>[a-z]+)是一个命名分组,?P<>是固定写法,<>里是自定义的命名,后面的[a-z]+才是实际要匹配的字符

    search()方法只匹配第一个结果就返回一个对象,这个对象的group()方法就能拿到匹配的结果nick20,其中nick就是name,22就是age,如果用group('name')就能拿到nick,这就是分组的好处,这种方法在以后开发时常用于匹配网址url。


    re模块下的常用方法

    re.findall(' ',' ')                  #返回所有满足匹配条件的结果,放在列表里。

    re.search(' ',' ').group()    #函数会在字符串内查找模式匹配,直到找到第一个匹配结果然后返回一个包含匹配信息的对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。

    re.match(' ',' ').group()     #同search,不过只在字符串开始处进行匹配。

    >>> re.match('d+','abc22')                           #开头没有数字,所以不匹配
    >>> re.match('d+','22abc')                           #开头有数字,匹配22
    <_sre.SRE_Match object; span=(0, 2), match='22'>
    >>> re.match('d+','22abc').group()
    '22'

    re.split(' ',' ')                     #分割字符串,类似于string里面的split(),如果是[]字符集,就按照里面的字符挨个分割

    >>> re.split('[ab]','hanbo')     #先按'a'分割得到'h'和'nbo',再对'h'和'nbo'按'b'分割得到'h', 'n', 'o'
    ['h', 'n', 'o'] 

    >>> re.split('[ab]','abo') #先按'a'分割得到''和'bo',再对''和'bo'按'b'分割得到'','','o'
    ['', '', 'o']

    re.sub('被替换的字符串','替换成什么字符串','待处理的整个字符串',替换几次)             #替换字符串

    >>> re.sub('d+','B','g23h578')    #匹配多个数字
    'gBhB'
    >>> re.sub('d','B','g23h578')     #匹配单个数字
    'gBBhBBB'
    >>> re.sub('d','B','g23h578',2)   #匹配单个数字,替换两次
    'gBBh578'

    re.subn()            #与sub的功能和参数都一样,唯一的不同是返回值:一个元组,其中第一个元素是处理后的结果,第二个元素是替换了几次

    >>> re.subn('d','B','g23h578',2)
    ('gBBh578', 2)
    >>> re.subn('d','B','g23h578',)
    ('gBBhBBB', 5)

    re.compile(' ')     #另一种写法而已,参数是匹配的规则,返回给一个对象,然后用这个对象去findall()或者search()

    >>> res = re.compile('d+')
    >>> res.findall('asd123ds')
    ['123']
    >>> res.search('as12kj34re')
    <_sre.SRE_Match object; span=(2, 4), match='12'>
    >>> res.search('as12kj34re').group()
    '12'

    这么做的好处是:用'd+'去处理多个字符串的时候,可以用res直接去处理,效率高。

    re.finditer(' ',' ')   #用法与findall()一模一样,只是不返回一个数组,而是一个迭代器

    >>> re.findall('d+','as12kj34re')
    ['12', '34']
    >>> re.finditer('d+','as12kj34re')
    <callable_iterator object at 0x0000029D51E6DB00>
    >>> res = re.finditer('d+','as12kj34re')
    >>> next(res).group()                              #迭代器用next()迭代取值
    '12'
    >>> next(res).group()
    '34'
    >>> next(res).group()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration

     这么做的好处是:通常我们处理的字符串都很庞大,如果都返回数组就要放入内存,消耗系统资源,而返回迭代器就可以想要什么数据只拿那个数据。

    补充:

    >>> re.findall('www.(baidu|taobao).com','www.taobao.com')
    ['taobao']

    当在匹配规则中使用()分组,Python解释器将默认优先匹配()中的字符串规则,而忽略外面的字符串规则

    >>> re.findall('www.(?:baidu|taobao).com','www.taobao.com')
    ['www.taobao.com']

    ?:就是去掉这个默认的优先级,不忽略外面的字符串规则

  • 相关阅读:
    2016个人测试1(待续。。。)
    bzoj2548[Cstc2002]灭鼠行动
    noip2013 积木大赛
    noip2013 火柴排队
    Noip2000 T3 单词接龙
    noip2017爆炸记——题解&总结&反省(普及组+提高组)
    【2017.10.26-】后缀数组学习笔记
    20171002清北
    【搜索党】卡时技巧
    【noip】noip201503求和(题解可能不完美,但绝对详细)
  • 原文地址:https://www.cnblogs.com/xulan0922/p/10242276.html
Copyright © 2011-2022 走看看