[python]正则表达式re

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

1/ 正则表达式的形式一般如下:
    / / 是定界符(或者叫界限符),例如/love/,其中位于"/"之间的部分就是要在目标对象中进行匹配的模式。用户只要把希望匹配的对象模式内容放入"/"定界符之间即可。
    \ 是转义符,例如\d,\s,\r,\n
    
2/ 较为常用的元字符包括: “+”, “*”,以及 “?”
    “+”元字符规定其前导字符必须在目标对象中连续出现一次或多次
    “*”元字符规定其前导字符必须在目标对象中出现零次或连续多次
    “?”元字符规定其前导对象必须在目标对象中连续出现零次或一次
    
    runoo+b,可以匹配 runoob、runooob、runoooooob 等,+ 号代表前面的字符必须至少出现一次(1次或多次)。
    runoo*b,可以匹配 runob、runoob、runoooooob 等,* 号代表前面的字符可以不出现,也可以出现一次或者多次(0次、或1次、或多次)。
    colou?r 可以匹配 color 或者 colour,? 问号代表前面的字符最多只可以出现一次(0次、或1次)。 
    
3/ 正则表达式元字符的具体应用:
    /fo+/ 因为上述正则表达式中包含“+”元字符,表示可以与目标对象中的 “fool”, “fo”, 或者 “football”等在字母f后面连续出现一个或多个字母o的字符串相匹配。 
    /eg*/ 因为上述正则表达式中包含“*”元字符,表示可以与目标对象中的 “easy”, “ego”, 或者 “egg”等在字母e后面连续出现零个或多个字母g的字符串相匹配。 
    /Wil?/ 因为上述正则表达式中包含“?”元字符,表示可以与目标对象中的 “Win”, 或者“Wilson”,等在字母i后面连续出现零个或一个字母l的字符串相匹配。

4/ 有时候不知道要匹配多少字符。为了能适应这种不确定性,正则表达式支持限定符的概念。这些限定符可以指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。

    {n} n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。 
    {n,} n 是一个非负整数。至少匹配 n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+''o{0,}' 则等价于 'o*'。 
    {n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。 
    

正则表达式可能遇到的坑:正则表达式中的括号()

<1> 当正则表达式中没有括号时,就是正常匹配,如下面例子中的"\w+\s+\w+"
      在本例中"/w+/s+/w+"第一次匹配到的字符为"2345  3456",由于是贪婪模式会     继续匹配,第二次从"4567"开始匹配匹配到的结果为字符串"4567 5678"
      import re
      string="2345  3456  4567  5678"
      regex=re.compile("\w+\s+\w+")
      print(regex.findall(string))
      #['2345 3456', '4567 5678']
      # 补充: 
      # \s -- 匹配任何不可见字符,包括空格、制表符、换页符等等 
      # \S -- 匹配任何可见字符 通常[/s/S] -- 可匹配任意字符
      # [\s\S]*? -- 匹配懒惰模式的任意字符


<2> 当正则表达式中有一个括号时,如"(\w+)\s+\w+"其输出的内容就是括号匹配到的内容
      原理:正则表达式中有一个括号时,其输出的内容就是括号内匹配到的内容,而不是整个表达式所匹配到的结果,但是整个正则表达式执行了,只不过只输出括号匹配到的内容,
      匹配过程:
      1. 第一次匹配时跟上述没有括号时一样,匹配到 "2345  3456",只不过只输出(\w+)匹配到的结果 即"2345",
      2. 第二次匹配同理从"4567" 开始,匹配到"4567  5678",但是,只输出"4567"
      import re
      string="2345  3456  4567  5678"
      regex1=re.compile("(\w+)\s+\w+")
      print(regex1.findall(string))
      #['2345', '4567']

<3> 当正则表达式中有两个括号时,如 "((\w+)\s+\w+)",其输出结果是一个list中包含2tuple
      从输出的结果可以看出,有两个元组,每一个元组中有   两个字符串 :
      其中,第一个元组种的第一个字符串"2345 3456"是最外面的括号输出的结果,第二个字符串是里面括号(\w+)输出的结果 "2345",
      第二个元组是第二次匹配的结果 -- 详解同第一次匹配。
      import re
      string="2345  3456  4567  5678"
      regex2=re.compile("((\w+)\s+\w+)")
      print(regex2.findall(string))
      #[('2345  3456', '2345'), ('4567  5678', '4567')]

<4> findall() 使用总结:
      第一个 regex 中不带有括号,其输出的内容就是整个表达式所匹配到的内容。
      第二个 regex 中带有1个括号,其输出的内容就是括号匹配到的内容,而不是整个表达式所匹配到的结果。
      第三个 regex 中是带有2个括号的,我们可以看到其输出是一个list 中包含2tuple,---  多个括号就会返回  多个括号分别匹配到的结果 
      有括号时只能匹配到括号中的内容,没有括号就正常匹配。
      在正则里面 “()” 代表的是分组的意思,一个括号代表一个分组,你只能匹配到"()"中的内容
      
############################################################################################################
############################################################################################################
正则表达式-常用函数

1.编译正则表达式:re.compile()
    >>>import re
    >>> r1=r"\d{3,4}-?\d{8}"
    >>> p_tel = re.compile(r1)  # 编译
    >>> p_tel
        <_sre.SRE_Pattern object at 0x00000000016A7C70>
    >>> p_tel.findall("01098769087")
        ['01098769087']

2.执行匹配
    (1match()(从字符串开始的位置匹配,如果开头匹配不上,就返回None)
          >>> a_re.match('csvt hello')
             <_sre.SRE_Match object at 0x0000000003A53030>
    (2)search()(找到re匹配的位置,返回匹配上的起止位置)
          >>> a_re.search('csvt hello')
             <_sre.SRE_Match object at 0x0000000003ACB7E8>
    (3)findall()(找到re匹配的所有子串并作为列表返回)
          >>> a_re.findall('finff csvt csvt hello')
             ['csvt', 'csvt']
    (4)finditer()(找到re匹配的所有子串并作为返迭代器回)
          >>> a_re.finditer('finff csvt csvt test csvt hello')
             <callable-iterator object at 0x00000000039F8AC8>

3/ re.I # 不区分大小写
      >>> a_re = re.compile(r'csvt',re.I)  # 编译,同时re.I代表不区分大小写,re.I要写在compile()函数里面
      >>> a_re.findall('CSVT')
          ['CSVT']

4/ MatchObject实例方法
    (1)group()(返回被re匹配的字符串)
    (2)start()(返回匹配开始的位置)
    (3)end()(返回匹配结束的位置)
    (4)span()(返回一个元组包含匹配(开始,结束)的位置)

      >>> x=a_re.match('csvt hello')
      >>> x
      <_sre.SRE_Match object at 0x0000000003ACB7E8>
      >>> x.group(0
      ... )
      'csvt'
      >>> x.group()
      'csvt'

5/模块级函数
    re模块顶级函数调用(match()\search()\sub()\subn()\split()\findall()等)
    >>> rs=r'c..t'
    >>> re.sub(rs,'python','csvt caat cvvt ccc')
    'python python python ccc'
    >>> re.subn(rs,'python','csvt caat cvvt ccc')
    ('python python python ccc', 3)

    >>> s="123+456-789*000"

    >>> re.split(r'[\+\-\*]',s)
    ['123', '456', '789', '000']

5.编译标志
    (1)I,大小写不敏感
    (2)S,使.匹配包括换行在内的所有字符

    >>> r1=r"csvt.net"
    >>> re.findall(r1,'csvt\tnet',re.S)
    ['csvt\tnet']

    (3)L,做本地化识别匹配
    (4)M,多行匹配,影响^和$

    >>> s='''
    ... hello csvt
    ... csvt hello
    ... hello csvt hello
    ... csvt hehe
    ... '''
    >>> r=r"^csvt"
    >>> re.findall(r,s,re.M)
    ['csvt', 'csvt']

(5)X,使用REs的 verbose状态
    >>> tel=r"""
    ... \d{3,4}
    ... -?
    ... \d{8}
    ... """
    >>> re.findall(tel,'010-12345678',re.X)
        ['010-12345678']

6.re属性-分组
    - "("")"
    >>> email=r"\w{3}@\w+(\.com|\.cn)"
    >>> re.findall(email,'zzz@csvt.com')
    ['.com']