• re 模块


    正则表达式是一种小型、高度专业化的编程语言。适用于任何语言,在 Python 中通过 re 模块实现。正则模式被编译成一系列的字节码,然后由 C 语言编写的匹配引擎执行。给字符串模糊匹配

    正则用于匹配字符串,匹配字符串可以完全匹配和模糊匹配:

    • 完全匹配:普通字符,大多数字符和字母都和自身匹配 re.findall('rose', 'lialrosetom')
    • 模糊匹配:元字符,不需要完全匹配即能匹配成功 . ^ $ * + ? { } [ ] | ( )

    元字符

    正则可以使用普通字符进行完全匹配,也可以使用元字符进行模糊匹配。正则表达式中所有元字符: . ^ $ * + ? { } [ ] | ( )

    通配符

    正则中用一个点(.)来表示通配符,它可以匹配除换行符( )以外任何字符。一个点只能匹配一个字符

    >>> re.findall('s..x', 'abshuxijd')	
    ['shux']
    

    开头结尾

    正则中尖角号(^)用于匹配一行字符串的开头,($)用于匹配一行字符串的结尾。必须以匹配对象开头或结尾才能匹配成功,否则匹配失败

    >>> re.findall(r'^hello,d+','hello,123')
    ['hello,123']
    >>> re.findall(r'^hello,d+','hi hello,123')
    []
    >>> re.findall(r'hello,d+$','hello,123')
    ['hello,123']
    >>> re.findall(r'hello,d+$','hello,123s')
    []
    

    重复匹配

    不管是点(.),还是数字匹配(d)都只能匹配一个字符或数字。要想匹配多个就要进行重复匹配,正则中能够重复匹配的元字符有:* + ? {}

    元字符 描述 元字符 描述
    * 对星号前面的子表达式匹配重复 [0, ∞] 次 + 对加号前面的子表达式匹配重复 [1, ∞] 次
    对问号前面的子表达式匹配重复 [0,1] 次,非贪婪模式 {n} 精确匹配 n 个前子表达式

    **星号 ***

    星号(*)可以对它前面的子表达式重复 0 次 或多次。

    # 对 abc 的 c 重复 0 到多次,即可匹配 ab、abc、abcc、abc...
    >>> re.findall(r'abc*','ab456abc123abccc')	
    ['ab', 'abc', 'abccc']
    

    加号 +

    加号(+)可以对它前面的子表达式重复 1 次或多次。

    >>> re.findall(r'abc+','ab456abc123abccc')			# 即至少有有一个 c
    ['abc', 'abccc']
    

    问号 ?

    问号(?)可以对它前面的子表达式重复 0 次或 1 次。

    >>> re.findall(r'abc?','ab456abc123abccc')
    ['ab', 'abc', 'abc']
    

    大括号 {}

    大括号({})可以对它前面的子表达式精确重复几次,它有多重模式:

    • {n} :对它前面的子表达式至少重复 n 次
    • {m, n} :对它前面的子表达式重复 m 到 n 次
    • {0, ∞} :相当于星号(*)
    • {1, ∞} :相当于加号(+)
    • {0, 1} :相当于问号(?)
    >>> re.findall(r'abc{3}','ab456abc123abccc')	# c 重复 3 次,匹配到 abccc
    ['abccc']
    >>> re.findall(r'abc{1,3}','ab456abc123abccc')  # 匹配 abc、abccc
    ['abc', 'abccc']
    >>> re.findall(r'abc{1,3}','abc456abcc123abccc')
    ['abc', 'abcc', 'abccc']
    

    管道符

    管道符(|)表示或,a|b 表示 a 或 b。

    >>> re.findall(r'a|b', 'abc')
    ['a', 'b']
    >>> re.findall(r'ka|b', 'kahbc')
    ['ka', 'b']
    >>> re.findall(r'ka|b', 'kahc')
    ['ka']
    >>> re.findall(r'ka|b', 'ka|bhc')
    ['ka', 'b']
    

    字符集

    在正则表达式中,中括号([ ] )表示一个字符集,它用来表示一组字符。字符集中除 - ^ 有特殊意义外,其他元字符都是普通字符。

    • [mm] :匹配 m 或 n
    • [^mn] :匹配除 m、n 以外的所有字符
    >>> re.findall(r'abc[de]','abcd123abce567')
    ['abcd', 'abce']
    >>> re.findall(r'[^de]+','abcd123abce567')
    ['abc', '123abc', '567']
    

    横杠 -

    字符集中横杠(-)用来表示范围,[a-z] 表示 a - z 任意一个字母。

    >>> re.findall(r'b[a-z]', 'bs')
    ['bs']
    >>> re.findall(r'[1-9]','12ab45')
    ['1', '2', '4', '5']
    >>> re.findall(r'[1-9]+','12ab45')
    ['12', '45']
    >>> re.findall(r'[A-Za-z0-9]+','12abCD45')
    ['12abCD45']
    
    >>> re.findall(r'd+@[A-Za-z0-9]+.[a-z]+','982561639@qq.com')
    ['982561639@qq.com']
    
    

    尖角号 ^

    尖角号(^)表示非,[^d] 除数字以外。

    >>> re.findall(r'[^d]+','abc123def')
    ['abc', 'def']
    >>> re.findall('b[^a-z]*', 'bs213')		# s 没有匹配上,匹配停止
    ['b']
    
    

    转义字符

    反斜杠()表示对某个字符转义,可以把普通字符变成特殊字符,如:d

    >>> re.findall(r'[d]+','abc123def456')
    ['123', '456']
    
    

    转义字符

    转义字符在元字符中是一个比较特殊的存在,在字符集里面、外面都有特殊意义。

    • 反斜杠后面跟元字符去除特殊功能,如:.,其中这个点变成了普通的点
    • 反斜杠后面跟普通字符实现特殊功能,如:d,匹配任何十进制数

    转义字符 + 普通字符 = 特殊字符

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

     在 Python 中本身是有特殊意义的,在匹配时,需要给它转义,或者加上原生字符串 r :

    >>> re.findall(r'abc','abc123')		#  匹配的是特殊字符边界,abc 后面没有空格,匹配失败
    []
    >>> re.findall('abc\b','abc 123')		# abc 后面有空格,匹配成功
    ['abc']
    >>> re.findall(r'abc','abc 123')
    ['abc']
    >>> re.findall(r'abc','abc#123')
    ['abc']
    
    

    给其他字符加上转义字符时:

    import re
    >>> re.findall('cl','abcle')
    []
    >>> re.findall('c\l','abcle')
    []
    >>> re.findall('c\\l','abcle')
    ['c\l']
    >>> re.findall(r'c\l','abcle')
    ['c\l']
    
    

    w 和 s 用法示例:

    >>> re.findall(r'w', '12shdk34_')		# 匹配数字字母以及下划线,加上+,匹配多个
    ['1', '2', 's', 'h', 'd', 'k', '3', '4', '_']
    >>> re.findall(r'w+', '12shdk34_')
    ['12shdk34_']
    
    >>> re.findall(r's+', '12 shdk 34_')	# 匹配空白字符
    [' ', ' ']
    
    

    Tips:在使用正则的时候,尽量带上原生字符串 r,可以避免不必要的麻烦。

    转义字符 + 元字符 = 普通字符

    给元字符加上转义字符,元字符就失去了原有的意义,变成了一个普通字符。

    >>> re.findall(r'www*', 'www*')
    ['www']
    >>> re.findall(r'www*', 'www*')	# 要想把 * 也匹配上,就要给 * 转义
    ['www*']
    
    

    贪婪与非贪婪

    关于重复匹配,正则表达式默认是按照贪婪匹配的方式去匹配,即在符合条件的情况下,尽可能多的去匹配。而非贪婪匹配恰好与之相反。

    贪婪匹配:

    >>> re.findall(r'abc*','abc123abcc')	# 尽可能多的匹配(* 的范围是 0 或 多次,它取了 多 次)
    ['abc', 'abcc']
    >>> re.findall(r'<.+>','<html><title>Hello World</title></html>')
    ['<html><title>Hello World</title></html>']
    
    
    

    启用非贪婪模式,只需在表示重复的元字符后面加上一个问号(?)即可:

    >>> re.findall(r'abc*?','abc123abcc')		# 尽可能少的匹配(* 的范围是 0 或 多次,它取了 0 次)
    ['ab', 'ab']
    >>> re.findall(r'<.+?>','<html><title>Hello World</title></html>')
    ['<html>', '<title>', '</title>', '</html>']
    
    

    在贪婪匹配下,(.*)会尽可能多的匹配字符,因此它把 123456 匹配了,只留下了一个 7 给 d+,最后得到的内容是 7 :

    >>> content = 'Hello 1234567 World_This a Regex Demo'
    >>> pattern = re.compile(r'^He.*(d+).*Demo$')
    >>> re.findall(pattern,content)
    ['7']
    
    

    有时贪婪匹配匹配的结果并不是我们想要的那样,给我们带来了很大不便,这时我们就要使用非贪婪匹配比较合适:

    >>> pattern = re.compile(r'^He.*?(d+).*Demo$')
    >>> re.findall(pattern,content)
    ['1234567']
    
    

    修饰符

    正则可以包含一些可选标志修饰符来控制匹配模式,修饰符被指定为一个可选的标志。

    常见修饰符
    修饰符 描述 修饰符 描述
    re.I 使匹配对大小不敏感 re.L 使本地化识别(locale-aware)匹配
    re.M 多行匹配,影响 ^ 和 $ re.S 使 . 匹配包含换行在内的所有字符(即点(.)换行符也能匹配)
    re.U 根据 Unicode 字符集解析字符。影响 w W  和 B reX 通过给与你更灵活的格式以便你将正则表达式写的更易理解

    我们知道点(.)可以匹配除换行符以外的所有字符,但是当遇到换行时,就会引发匹配失败:

    import re
    content = """Hello 1234567 World_This
    is a Regex Demo"""
    result = re.match(r'^He.*?(d+).*?Demo$',content)
    print(result.group(1))
    
    
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-2-bd9088917b1a> in <module>()
          3 is a Regex Demo"""
          4 result = re.match(r'^He.*?(d+).*?Demo$',content)
    ----> 5 print(result.group(1))
    
    AttributeError: 'NoneType' object has no attribute 'group'
    
    

    之所以会报没有 group 方法,是因为我们使用了点(.)匹配任意字符,但是不能匹配换行符,也就匹配失败。而我们又调用了 group 方法,针对这种情况,我们只需在 match 方法最后添加一个 re.S 的修饰符即可,以便使点(.)能匹配换行:

    result = re.match(r'^He.*?(d+).*?Demo$',content,re.S)
    
    1234567
    
    

    分组

    分组优先匹配组里面的内容,也只显示括号里面的。要想全部显示可以在括号前面加上(?:),进行去优先级:

    >>> re.findall('www.(baidu|163).com', 'www.baidu.com')
    ['baidu']
    
    # 在分组前面加上  ?:	表示去组的优先级
    >>> re.findall('www.(?:baidu|163).com', 'www.baidu.com')
    ['www.baidu.com']
    
    >>> re.findall('(abc)+', 'abcabcabc')
    ['abc']
    >>> re.findall('(?:abc)+', 'abcabcabc')
    ['abcabcabc']
    
    

    分组后的结果通过 group() 方法即可取到:

    >>> re.match(r'^th.*?(d+).*?(d+)','this is 123456 regex 567')
    <_sre.SRE_Match object; span=(0, 24), match='this is 123456 regex 567'>
    >>> re.match(r'^th.*?(d+).*?(d+)','this is 123456 regex 567').group()
    'this is 123456 regex 567'
    >>> re.match(r'^th.*?(d+).*?(d+)','this is 123456 regex 567').group(1)
    '123456'
    >>> re.match(r'^th.*?(d+).*?(d+)','this is 123456 regex 567').group(2)
    '567'
    
    

    另一种分组方式,?P<组名>,通过组名取值,当匹配的结果有很多时,可以这样取值 :

    # 另一种分组方式,?P<组名> ,通过组名取值,当匹配的结果有很多时,可以这样取值 
    >>> re.search("(?P<name>[a-z]+)", "rose18john20tom22")               
    <_sre.SRE_Match object; span=(0, 4), match='rose'>     
    >>> re.search("(?P<name>[a-z]+)", "rose18john20tom22").group()
    'rose'
    
    >>> re.search("(?P<name>[a-z]+)", "rose18john20tom22").group('name')      # 名字分组为 name         'rose'                                                                
    >>> re.search("(?P<name>[a-z]+)(?P<age>d+)", "rose18john20tom22").group('age')    # 名字分组为 age '18'                                              
    
    

    re 模块常用方法

    match 方法

    match(patter, string, flags=0) 方法从字符串开始位置匹配,如果匹配成功则返回匹配位置以及 match 对象,否则返回 None。

    第一个参数为正则表达式,第二个参数为待匹配的字符串。

    >>> re.match('d', 'rose56')
    >>> re.match('d', '12rose56')
    <_sre.SRE_Match object; span=(0, 1), match='1'>
    >>> re.match('d', '12rose56').group()
    '1'
    
    

    search 方法

    search(pattern, string, flags=0)方法扫描整个字符串,搜索正则表达式模式匹配的第一个位置,并返回 match 对象。如果没有与之匹配的,则返回 None。正则表达式模式即为匹配规则,需要用原生字符串来写,避免不必要的麻烦。

    第一个参数为正则表达式,第二个参数为待匹配的字符串。

    >>> re.search(r'abc', 'abc123abc')
    <_sre.SRE_Match object; span=(0, 3), match='abc'>	# 返回第一个匹配结果的位置,以及 match 对象
    
    

    使用 group() 方法可以拿到匹配结果:

    >>> result = re.search(r'abc', 'abc123abc')
    >>> result.group()
    'abc'
    
    

    使用 span() 方法可以拿到匹配结果范围:

    >>> result = re.search(r'abc', 'abc123abc')
    >>> result.span()
    (0, 3)
    
    

    split 方法

    split(pattern, string, maxsplit=0, flags=0)分割字符串,返回结果存储到列表中,maxsplit 为早打分割次数。

    >>> re.split(' ', 'hi hello six')	# 按空格分
    ['hi', 'hello', 'six']
    >>> re.split('[ |]', 'hi hello|six')	# 按空格或 | 分
    ['hi', 'hello', 'six']
    >>> re.split('[ab]', 'abc')		# 先按 a 分(a的左边为空,因此分为 '' 和 'bc'),再按 b 分(b 的左边为空,因此分为 '' 和 'c'
    ['', '', 'c']
    
    

    sub 方法

    sub(pattern, repl, string, count=0, flags=0) 方法替换原字符串某个文本,第一个参数为正则,第二个为替换成的字符串,第三个为原字符串,第四个为替换次数。并返回替换后的字符串。

    >>> re.sub(r'd+', 'A', 'abcd12df45')
    'abcdAdfA'
    >>> re.sub(r'd+', 'A', 'abcd12df45', 1)
    'abcdAdf45'
    
    

    subn() 方法可以返回替换次数:

    >>> re.subn(r'd+', 'A', 'abcd12df45')	
    ('abcdAdfA', 2)
    
    

    compile 方法

    前面我们都是直接在 re 方法中使用正则,re 模块提供了一个 compile() 方法可以将正则编译成正则对象,以便匹配规则可以重复使用。

    pattern = re.compile(r'd+')
    
    

    其他方式直接传入正则对象即可:

    >>> content = '2018-11-17 17:18'
    >>> pattern = re.compile(r'd{2}:d{2}')
    >>> result = re.findall(pattern,content)
    >>> result
    ['17:18']
    
    

    finditer 方法

    finditer(pattern, string, flags=0) 方法与 findall() 方法类似 ,不同的是前者将匹配结果封装成一个迭代器,而后者将全部匹配结果存为一个列表。

    >>> ret = re.finditer('d+', 'ss123dd456')
    >>> next(ret).group()
    '123'
    
    

    findall 方法

    search() 方法返回匹配结果的第一个内容,要想获得所有匹配内容。就需要借助 findall(pattern, string, flags=0) 方法,它会搜索整个字符串,并将匹配结果存到一个列表中。若没有匹配成功,则返回一个空列表。

    >>> re.findall(r'd+','12so45ch')
    ['12', '45']
    
    
  • 相关阅读:
    flash 3d基础学习
    3d中的镜头
    [转]Android Canvas 切割 clipRect
    绘制球形
    绘制圆筒
    stage3d学习笔记1
    (转)Region.Op效果解析
    游戏中的镜头
    无向网的最小生成树——Prim算法(转)
    最短路径之——Dijkstra算法(转)
  • 原文地址:https://www.cnblogs.com/midworld/p/10847320.html
Copyright © 2020-2023  润新知