zoukankan      html  css  js  c++  java
  • python-正则表达式

    正则表达式(RE)是一些由字符和特殊字符组成的字符串,它们描述了这些字符和字符的某种重复方式,因此能按照某种模式匹配一个有相似特征的字符串的集合,因此能按某种模式匹配一系类有相似特征的字符串。

    Python通过标准库re模块支持正则表达式。

    说明一下术语“匹配”和“搜索”的区别:

    Python专门术语中,有两种主要方法完成匹配:搜索和匹配。搜索:即在字符串任意部分中搜索匹配的模式。匹配:判断一个字符能否从开始处全部或部分的匹配某个模式。搜索通过search()函数或方法实现,匹配调用match()函数或方法实现。我们说模式的时候,使用的是术语“匹配”。

    1.1 正则表达式使用的特殊符号和字符

    记号

    说明

    正则表达式样例

    literal

    匹配字符串的值

    foo

    re1/re2

    匹配正则表达式re1或re2

    foo|bar

    .

    匹配任意字符(换行符除外)

    b.b

    ^

    匹配字符串的开始

    ^Dear

    $

    匹配字符串的结尾

    /bin/*sh$

    *

    匹配前面出现的正则表达式零次或多次

    [A-Za-z0-9]*

    +

    匹配前面出现的正则表达式出现一次或多次

    [a-z]+.com

    ?

    匹配前面出现的正则表达式零次或一次

    goo?

    {N}

    匹配前面出现的正则表达式N

    [0-9]{3}

    {M,N}

    匹配重复出现M次到N次的正则表达式

    [0-9]{5,9}

    […]

    匹配字符组里出现的任意一个字符

    [aeiou]

    [.,x-y,.]

    匹配从字符x到字符中的任意一个字符

    [0-9],[A-Za-z]

    [^…]

    不匹配此字符集中出现的任意一个字符,包括某一范围的字符(如果在此字符集中出现)

    [^aeiou],[^A-Za-z0-9]

    (*|+|?|{})?

    用于上面出现的任何“非贪婪”。版本重复匹配次数符号

    .*?[a-z]

    (…)

    匹配封闭括号中正则表达式(RE),并保存为子组

    ([0-9]{3})?,f(oo|u)bar

    特殊字符

    d

    匹配任何数字,和[0-9]一样,(D是d的反义,任何非数符字)

    datad+.txt

    w

    匹配任何数字字母字符,和[A-Za-z0-9_]相同,(W是w的反义)

    [A-Za-z_]w+

    s

    匹配任何空白符,和[ vf]相同。(S是s的反义)

    ofsthe

    

    匹配单词边界。(B是的反义)

    The

    n

    匹配已保存的子组

    prince:16

    c

    逐一匹配特殊字符c(即:取消它的特殊含义,按字面匹配)

    .,\, *

    A()

    匹配字符串的起始(结束)

    ADear

    (1)用管道符号(|)匹配多个正则表达式模式

    管道符号(|),表示一个或操作,它的意思是选择被管道符号分割的多个不同的正则表达式中的一个。

    (2)匹配任意一个单个的字符(.)

    点符号或句点(.)符号匹配除换行符(NEWLINE)外的任意一个单个字符(Python的正则表达式有一个编译标识[S or DOTALL]),该标识能去掉这一限制,使(.)      在匹配时包括换行符。无论是字母、数字、不包括“ ”的空白符、可打印的字符、还是非打印字符,或是一个符号,点(.)都可以匹配它们。

    (3)从字符串的开头或结尾或单词边界开始匹配(^ $  B)

    ^或A:用于从字符串的开头开始匹配一个模式。

    如果想匹配这两个字符中的任何一个(或全部),就必须用反斜线进行转义。

    或B:用来匹配单词边界,匹配的模式是一个单词边界(一定在一个单词的开头,不论这个单词的前面是有字符,还是没有字符),B只匹配出现在一个单词中间的模式(不在单词边界上的字符)。

    (4)创建字符类([])

    使用方括号的正则表达式会匹配方括号里的任意一个字符。

    (5)指定范围(-)和否定(^)

    方括号里的一对字符中间的连字符(-)用来表示一个字符的范围。例如:z.[0-9]

    如果左方括号后第一个字符是上箭头符号(^),就表示不匹配指定字符集里的任意字符。例如:[^aeiou]

    (6)使用闭包操作符(*,+,?,{})实现多次出现/重复匹配

    *:匹配它左边那个正则表达式出现零次或零次以上的情况。

    +:匹配它左边那个正则表达式至少出现一次的情况。

    ?:匹配它左边那个正则表达式出现零次或一次的情况。

    {N}:匹配N次出现。

    {M,N}:匹配M次到N次出现。

    (7)特殊字符表示

    d:0-9范围内的十进制数。

    w:整个字符数字的字符集,相当于“A-Za-z0-9_”。

    s:表示空白字符。

    这些特殊字符的大写形式表示不匹配。

    (8)用圆括号(())组建组

    一对圆括号(())和正则表达式使用实现的功能有:1.对正则表达式进行分组;2.匹配子组。

    使用圆括号匹配的子串会被保存到一个子组。这些字组可以在同一次匹配或搜索中被重复调用。

    1.2 正则表达式和Python语言

    1.2.1 re模块:核心函数和方法

    常用的函数和方法:

    函数/方法

    描述

    模块的函数

    compile(pattern, flags=0)

    对正则表达式模式pattern进行编译,flags是可选标识符,并返回一个regex对象(已编译的正则表达式对象)。

    re模块的函数和regex对象的方法

    match(pattern, string, flags=0)

    尝试用正则表达式pattern匹配字符串string,flags是可选标识符,如果匹配成功,则返回一个匹配对象,否则返回None

    search(pattern, string, flags=0)

    在字符串string中搜索正则表达式模式pattern的第一次出现,flags是可选标识符,如果匹配成功,则返回一个匹配对象,否则返回None。

    findall(pattern, string, [,flags])

    在字符串string中搜索正则表达式模式pattern的所有(非重复)出现,返回一个匹配对象的列表。

    finditer(pattern, string [,flags])

    和findall()相同,但返回的不是列表而是迭代器;对于每个匹配,该迭代器返回一个匹配对象。

    split(pattern, string, max=0)

    根据正则表达式pattern中的分隔符把字符string分割为一个列表,返回成功匹配的列表,最多分割max次(默认是分割所有匹配的地方)。

    sub(pattern, repl, string, max=0)

    把字符串中所有匹配正则表达式pattern的地方替换成字符串repl,如果max的值没有给出,则对所有匹配的地方进行替换。

    匹配对象的方法

    group(num=0)

    返回全部匹配对象(或指定编号是num的子组)

    groups()

    返回一个包含全部匹配的子组的元组(如果没有成功匹配,就返回一个空元祖)。

    RE编译(何时应该使用compile函数?)

    在模式匹配之前,正则表达式模式必须先被编译成regex对象,由于正则表达式在执行过程中被多次用于比较,建议先对它做预编译。re.compile()函数提供了此功能。

    1.2.2 匹配对象和group()、groups()方法

    在处理正则表达式中,出regex对象外,还有一种对象类型-匹配对象,通过match()函数和search()函数被成功调用后返回。匹配对象有两个主要方法:group()和groups()。

    group():或返回所有匹配对象或根据要求返回某个特定子组。

    groups():返回一个包含唯一或所有子组的元组。

    1.2.3 用match()匹配字符串

    match():从字符串开头开始对模式进行匹配,如果匹配成功,返回一个匹配对象,如果失败,返回None。匹配对象的group()方法可以用来显示那个成功的匹配。

     1 m = re.match('foo', 'foo')
     2 >>> if m is not None: 
     3 ...     m.group()    
     4 ... 
     5 'foo'
     6 >>> m
     7 <_sre.SRE_Match object at 0x7f4e059a9648>
     8 >>> m = re.match('foo', 'food on table') 
     9 >>> m.group()
    10 'foo'

    1.2.4 search()在一个字符串中查找一个模式

    search():检查参数字符串任意位置的地方给定正则表达式的匹配情况,如果搜索到成功的匹配,会返回一个匹配对象,否则返回None。

    1 >>> m = re.match('foo', 'seafood')
    2 >>> m.group()
    3 Traceback (most recent call last):
    4   File "<stdin>", line 1, in <module>
    5 AttributeError: 'NoneType' object has no attribute 'group'
    6 >>> m = re.search('foo', 'seafood').group()
    7 >>> m
    8 'foo'

    1.2.5 匹配多个字符串(|)

     1 >>> bt = 'bat|bet|bit'
     2 >>> m = re.match(bt, 'bat')
     3 >>> m
     4 <_sre.SRE_Match object at 0x7f4e059a9ac0>
     5 >>> m.group()
     6 'bat'
     7 >>> m = re.match(bt, 'bit')
     8 >>> m.group()              
     9 'bit'
    10 >>> m = re.match(bt, 'bet')
    11 >>> m.group()              
    12 'bet'

    1.2.6 匹配任意单个字符(.)

    句点是不能匹配换行符或非字符(即空字符)的。

     1 >>> m = re.match(anyend, 'bend')
     2 >>> if m is not None: m.group()   
     3 ... 
     4 'bend'
     5 >>> m = re.match(anyend, '
    end') 
     6 >>> if m is not None: m.group()   
     7 ... 
     8 >>> m = re.match(anyend, 'end')
     9 >>> if m is not None: m.group()
    10 ... 
    11 >>> m = re.match(anyend, 'the end')
    12 >>> 
    13 >>> if m is not None: m.group()    
    14 ... 
    15 >>>
    16 >>> patt314 = '3.14'
    17 >>> pi_patt = '3.14'
    18 >>> m = re.match(pi_patt, '3.14')
    19 >>> if m is not None:m.group()
    20 ... 
    21 '3.14'
    22 >>> m = re.match(patt314, '3014')    
    23 >>> if m is not None:m.group()   
    24 ... 
    25 '3014'
    26 >>> m = re.match(patt314, '3.14')
    27 >>> if m is not None:m.group()   
    28 ... 
    29 '3.14'
    30 >>>

    1.2.7 创建字符合集([])

     1 >>> m = re.match('[cr][23][dp][o2]', 'c3po')
     2 >>> if m is not None:m.group()              
     3 ... 
     4 'c3po'
     5 >>> m = re.match('[cr][23][dp][o2]', 'c2po')
     6 >>> 
     7 >>> if m is not None:m.group()              
     8 ... 
     9 'c2po'
    10 >>> m = re.match('r2d2|c3po', 'c2po')                   
    11 >>> 
    12 >>> if m is not None:m.group()       
    13 ... 
    14 >>> m = re.match('r2d2|c3po', 'r2po')
    15 >>> if m is not None:m.group()       
    16 ... 
    17 >>> m = re.match('r2d2|c3po', 'r2d2')
    18 >>> 
    19 >>> if m is not None:m.group()       
    20 ... 
    21 'r2d2'
    22 >>>

    1.2.8 重复、特殊字符和子组

    例如下面的例子,表达式容许“.com”前面有一个或两个名字:

    1 >>> patt = 'w+@(w+.)?w+.com' 
    2 >>> re.match(patt, 'nobody@xxx.com').group()
    3 'nobody@xxx.com'

    接着修改,允许任意数量的子域存在。

    1 >>> patt = 'w+@(w+.)*w+.com' 
    2 >>> re.match(patt, 'nobody@xxx.yyy.zzz.com').group() 
    3 'nobody@xxx.yyy.zzz.com'

    分别提取包含字母或数字的部分或仅含有数字的部分。

    1 >>> m = re.match('(www)-(ddd)', 'abc-123') 
    2 >>> m.group()
    3 'abc-123'
    4 >>> m.group(1) 
    5 'abc'
    6 >>> m.group(2) 
    7 '123'
    8 >>> m.groups() 
    9 ('abc', '123')

    group()通常用来显示所有匹配部分,也可以用来获取个别匹配的子组,groups()方法获得一个包含所有匹配子组的元组。

     1 >>> m = re.match('ab', 'ab') 
     2 >>> m.group()
     3 'ab'
     4 >>> m.groups() 
     5 ()
     6 >>> m = re.match('(ab)', 'ab') 
     7 >>> m.group()  
     8 'ab'
     9 >>> m.group(1) 
    10 'ab'
    11 >>> m.groups() 
    12 ('ab',)
    13 >>> m = re.match('(a)(b)', 'ab') 
    14 >>> m.group()  
    15 'ab'
    16 >>> m.group(1) 
    17 'a'
    18 >>> m.group(2) 
    19 'b'
    20 >>> m.groups() 
    21 ('a', 'b')
    22 >>> m = re.match('(a(b))', 'ab') 
    23 >>> m.group()  
    24 'ab'
    25 >>> m.group(1) 
    26 'ab'
    27 >>> m.group(2) 
    28 'b'
    29 >>> m.groups() 
    30 ('ab', 'b')

    1.2.9 从字符串的开头或结尾匹配及在单词边界上的匹配

    这些是锚点性正则表达式,这些锚点性正则表达式主要用于搜素而不是匹配,因为match()总是从字符串的开头进行匹配的。

     1 >>> m = re.search('^The', 'The end')  #在开头
     2 >>> if m is not None:m.group()
     3 ... 
     4 'The'
     5 >>> m = re.search('^The', 'end. The') 
     6 >>> if m is not None:m.group()        
     7 ... 
     8 >>> m = re.search(r'the', 'bite the dog')  #在词边界
     9 >>> if m is not None:m.group()
    10 ... 
    11 'the'
    12 >>> m = re.search(r'the', 'bitethe dog')  
    13 >>> if m is not None:m.group()
    14 ... 
    15 >>> m = re.search(r'Bthe', 'bitethe dog')  #不在词边界
    16 >>> if m is not None:m.group()
    17 ... 
    18 'the'

    1.2.10 用findall()找到每个出现的匹配部分

    findall():用于非重叠的搜索某字符串中一个正则表达式模式出现的情况。返回的总是一个列表,如果没有匹配,返回空列表;如果成功找到匹配部分,则返回所有匹配部分的列表(按从左到右出现的顺序排列)。

    1 >>> re.findall('car', 'car') 
    2 ['car']
    3 >>> re.findall('car', 'scary') 
    4 ['car']
    5 >>> re.findall('car', 'carry the barcardi to the car') 
    6 ['car', 'car', 'car']

    1.2.11 用sub()(和subn())进行搜索和替换

    两者几乎一样,都是将某字符串中所有匹配正则表达式模式的部分进行替换。用来替换的部分通常是一个字符串,但也可能是一个函数,该函数返回一个用来替换的字符串。

    subn()还返回一个表示替换次数的数字,替换后的字符串和表示替换次数的数字作为一个元组的元素返回。

     1 >>> re.sub('X', 'Mr.Smith', 'attn: X
    
    Dear X,
    ') 
     2 'attn: Mr.Smith
    
    Dear Mr.Smith,
    '
     3 >>> re.subn('X', 'Mr.Smith', 'attn: X
    
    Dear X,
    ') 
     4 ('attn: Mr.Smith
    
    Dear Mr.Smith,
    ', 2)
     5 >>> print re.sub('X', 'Mr.Smith', 'attn: X
    
    Dear X,
    ') 
     6 attn: Mr.Smith
     7 
     8 Dear Mr.Smith,
     9 
    10 >>> re.sub('[ae]', 'X', '[abcdef]') 
    11 '[XbcdXf]'
    12 >>> re.subn('[ae]', 'X', '[abcdef]') 
    13 ('[XbcdXf]', 2)
    14 >>> 

    1.2.12 用split()分隔(分隔模式)

    根据固定的字符串分隔。

    1 >>> re.split(':', 'str1:str2:str3') 
    2 ['str1', 'str2', 'str3']

    例子:Linux下who命令输出结果进行分隔

    #!/usr/bin/env python
    
    from os import popen
    from re import split
    
    f = popen('who', 'r')
    for eachline in f.readlines():
        print split('ss+|	', eachline.strip())
    f.close()
    输出结果:
    [root@localhost tmp]# python rewho.py 
    ['grace', 'tty1', '2020-01-26 14:18 (:0)']
    ['grace', 'pts/0', '2020-01-26 14:18 (:0.0)']
    ['root', 'pts/1', '2020-01-26 14:19 (192.168.230.1)']

    核心笔记:python原始字符串的用法

    原生字符串的产生是由于正则表达式的存在,由于ASCLL字符和正则表达式特殊字符间产生的冲突。例如“”在ASCLL字符中代表退格符,但同时也是一个正则表达式的特殊字符,代表“匹配一个单词边界”。为了让RE编辑器把两个字符‘’当成想要表达的字符串,可以是用r’’。

     1 >>> m = re.match('blow', 'blow')
     2 >>> if m is not None:m.group()
     3 ... 
     4 >>> m = re.match('\bblow', 'blow')
     5 >>> 
     6 >>> if m is not None:m.group()     
     7 ... 
     8 'blow'
     9 >>> m = re.match(r'blow', 'blow') 
    10 >>> if m is not None:m.group()     
    11 ... 
    12 'blow'

    1.3 正则表达式示例

    1.3.1 正则表达式示例

    下面展示使用正则表达式处理字符串的不同办法。第一步:拿出一段代码用来生成随机数据,生成的数据用于以后操作。

     1 from random import randint, choice
     2 from string import lowercase
     3 from sys import maxint
     4 from time import ctime
     5 
     6 doms = ['com', 'edu', 'net', 'org', 'gov']
     7 
     8 for i in range(randint(5, 10)):
     9     dtint = randint(0, maxint-1)
    10     dtstr = ctime(dtint)
    11     shorter = randint(4, 7)
    12     em = ''
    13     for j in range(shorter):
    14         em += choice(lowercase)
    15 
    16     longer = randint(shorter, 12)
    17     dn = ''
    18     for j in range(longer):
    19         dn += choice(lowercase)
    20     
    21     print '%s::%s@%s.%s::%d-%d-%d' % (dtstr, em, dn, choice(doms), dtint, shorter, longer)

    接下来使用生成的字符串来进行测试:

    测试1:提取时间戳中的有关星期的数据字段

     1 >>> data = 'Fri Sep  7 08:10:38 2035::vjxod@dgolkl.edu::2072736638-5-6'
     2 >>> patt = '^(Mon|Tue|Wed|Thu|Fri|Sat|Sun)'
     3 >>> m = re.match(patt, data)
     4 >>> m.group()
     5 'Fri'
     6 >>> m.group(1)
     7 'Fri'
     8 >>> m.groups()
     9 ('Fri',)
    10 >>>

    测试2:测试1例子的宽松表示

    1 >>> data
    2 'Fri Sep  7 08:10:38 2035::vjxod@dgolkl.edu::2072736638-5-6'
    3 >>> patt = '^(w{3})'
    4 >>> m = re.match(patt, data)
    5 >>> m.group()
    6 'Fri'
    7 >>> m.group(1)
    8 'Fri'
    9 >>>

    1.3.2 搜索与匹配的比较,“贪婪”匹配

    例如我们要搜索三个连字符号(-)分隔的整型集。

     1 >>> data
     2 'Fri Sep  7 08:10:38 2035::vjxod@dgolkl.edu::2072736638-5-6'
     3 >>> patt = 'd+-d+-d'
     4 >>> re.search(patt, data).group()
     5 '2072736638-5-6'
     6 >>> patt = '.+d+-d+-d+'
     7 >>> re.match(patt, data).group()
     8 'Fri Sep  7 08:10:38 2035::vjxod@dgolkl.edu::2072736638-5-6'
     9 >>> patt = '.+(d+-d+-d+)'    
    10 >>> re.match(patt, data).group()
    11 'Fri Sep  7 08:10:38 2035::vjxod@dgolkl.edu::2072736638-5-6'
    12 >>> re.match(patt, data).group(1)
    13 '8-5-6'

    出现上面的原因是:正则表达式本身默认是贪心匹配的。也就是说,如果正则表达式中使用到通配字,那它在按照从左到右的顺序求值时,会尽量“抓取”满足匹配的最长字符串。在上面的例子中,“.+”会从字符串的开始处抓取满足模式的最长字符,其中包含我们想得到的第一个整型字符起始到这个第一位数字“8”之间的所有字符。

    一个解决办法是用“非贪婪”操作符“?”。这个操作符可以用在“*”、“+”或“?”的后面。它的作用是要求正则表达式引擎匹配的字符越少越好。

    1 >>> patt = '.+?(d+-d+-d+)'    
    2 >>> re.match(patt, data).group(1)
    3 '2072736638-5-6'
    4 >>>

    示例3:假设我们只想抽取三个整型字段里中间的那个整型部分

    1 >>> data = 'Fri Sep  7 08:10:38 2035::vjxod@dgolkl.edu::2072736638-5-6'
    2 >>> patt = '-(d+)-'
    3 >>> m = re.search(patt, data)
    4 >>> m.group()
    5 '-5-'
    6 >>> m.group(1)
    7 '5'
    8 >>>
  • 相关阅读:
    mac配置git和github
    更新hosts后,如何清理edge的DNS缓存
    初次运行 Git 前的配置
    mac安装homebrew
    xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
    AJAX
    HTTP协议
    HTTP状态码大全
    SQL Servers数据库_删除
    Hello Word
  • 原文地址:https://www.cnblogs.com/mrlayfolk/p/12235021.html
Copyright © 2011-2022 走看看