zoukankan      html  css  js  c++  java
  • python day6 装饰器补充,正则表达式

    python day 6

    2019/10/09

    学习资料来自老男孩教育

    1. 装饰器decorator

    一旦挂上装饰器,函数就会变成装饰器的inner函数。
    1.1. 接收任意个参数的装饰器。

    def outter(func):
        def inner(*args,**kwargs):
            print(123)
            ret = func(*args,**kwargs)
            print(456)
            return ret
        return inner
    
    @outter
    def hello(name):
        print('hello %s' % name)
    hello('lanxing')
    

    1.2. 多个装饰器装饰同一个参数

    def outter1(func):
        def inner(*args,**kwargs):
            print(123)
            ret = func(*args,**kwargs)
            print(456)
            return ret
        return inner
    
    def outter2(func):
        def inner(*args,**kwargs):
            print(123)
            ret = func(*args,**kwargs)
            print(456)
            return ret
        return inner
    
    @outter1
    @outter2
    def hello(name):
        print('hello %s' % name)
    
    hello('lanxing')
    

    2. 正则表达式re

    2.1 正则表达式概述

    在开发中会有大量的字符串处理工作,其中经常会涉及到字符串格式的校验
    例如:如何判断一个字符串是不是手机号(检测用户填写)
    17611105750
    11位;数字组成不能包含其他字符;1开头;第二位是3,4,5,7,8
    如何将以上规则描述出来,让计算机可以识别,就是正则表达式要完成的工作。
    正则表达式是一个特殊的字符序列:用来描述某个规则
    正则表达式的大致匹配过程是:依次拿出表达式(规则)和文本中的字符比较,如果每一个字符都能匹配,则匹配成功;一旦有匹配不成功的字符则匹配失败。
    它能帮助你方便的检查一个字符串是否与某种模式匹配,也叫正规表示法、规则表达式、常规表示法。。。等等。常简写为RE。
    英语:Regular Expression 这里的regular指‘规则’
    Regular Expression 即 “描述某种规则的表达式”

    正则表达式并不是Python的一部分
    正则表达式是用于处理字符串的工具,拥有自己独特的语法以及一个独立的处理引擎,在提供了正则表达式的语言里,正则表达式的语法都是一样的。
    (不同的编程语言支持的语法数量不同)

    Python中需要通过正则表达式对字符串进⾏匹配的时候, 使⽤re模块。
    re 模块是Python当中提供的正则表达式工具包,使Python语言拥有全部的正则表达式功能

    2.2 re模块常用方法

    • match(匹配)

    使用match方法进行匹配操作:
    re.match 尝试从字符串的起始位置匹配一个模式

    re.match(正则表达式,要匹配的字符串):

    1. match方法的第一个参数接收的是描述某个规则的字符串.
    2. 第二个参数是要进行校验的值.
    3. 从左向右开始匹配.

    re.match()是用来进行匹配检查的方法,若正则表达式与字符串规则匹配,则返回匹配对象(Match Object),否则返回None.
    匹配对象Match Object具有一个group方法,用来返回字符串中匹配的部分.
    (如果匹配到数据的话, 可以使⽤group⽅法来提取匹配到的数据).

    import re
    line = 'qwertyuiop'    #不具备通用性
    s = "qwertyuiopl"
    print(re.match(line, s).group())
    
    
    import re
    line = 'Hello 123 4567 World_This is a Regex Demo'
    result = re.match('Hellosdddsd{4}sw{10}', line)
    print(result)
    print(result.group())
    
    • 表示字符
    字符 功能 备注
    . 点号表示匹配任意一个字符
    [] 匹配中括号[]里面的一个字符
    d 表示0-9之间的数字,包括0与9 相当于[0-9]
    D 表示除了0-9的字符,即d的取反 相当于[^0-9]
    w 匹配单词字符,即0-9,a-z,A-Z以及下划线_ 相当于[0-9a-zA-Z_]
    W 匹配非单词字符 相当于[^0-9a-zA-Z_]
    s 匹配空白符,即空格键,tab键 ,换行
    S 匹配非空白符

    正则表达式⾥使⽤“”作为转义字符(d)。
    由于正则表达式使用反斜杠来转义特殊字符,而python自身处理字符串时,反斜杠也是用于转义字符,这样就产生了一个双重转换的问题
    假如你需要匹配⽂本中的字符"", 那么使⽤正则表达式⾥将需要4个反斜杠"": 前两个和后两个分别⽤于在编程语⾔⾥转义成反斜杠, 转换成两个反斜杠后再在正则表达式⾥转义成⼀个反斜杠。
    Python中字符串前⾯加上 r 表示原⽣字符串(真实字符串)
    原⽣字符串很好地解决了上面的这个问题, 有了原始字符串, 你再也不⽤担⼼是不是漏写了反斜杠。
    'r'是防止字符转义的 如果路径中出现' '的话 不加r的话 就会被转义 而加了'r'之后' '就能保留原有的样子。
    所以以后凡是使用正则表达式,就先加上r。
    ret = re.match(r"c:\a", "c:\a\b\c" )
    ret.group()
    从字符串输入到代码转义一次,又在生成正则表达式的时候再转义一次,于是就需要多打反斜杠。用r""可以抵消掉第一次转义.
    r只抵消第一次转义:python正则表达式加了r之后w,s,.这些有含义的字符仍然有效.

    • 表示数量
    字符 功能
    * 匹配前一个字符0次或多次,即可有可无,d*表示匹配0个或多个数字
    + 匹配前一个字符1次或多次,即至少一次
    ? 匹配前一个字符1次或0次,即要么有1次,或者0次
    {m} 匹配前一个字符m次
    {m,} 匹配前一个字符至少m次或无限次
    {m,n} 匹配前一个字符从m次到n次,可以替代*+?
    • 表示边界
    字符 功能
    ^ 匹配字符串开头,(必须以某个条件开头)
    $ 匹配字符串结尾
     匹配单词边界,需要加r
    B 匹配非单词边界
    print(re.match('^The', 'The end').group())
    匹配以The开头的字符串
    
    print(re.match('w*send$', 'The end').group())
    匹配必须以end结尾
    print(re.match(‘w*send$’, ‘The endd’).group()) #出错
    
    `re.match(r".*ver", "ho ver abc").group()`
    `re.match(r".*ver", "ho verabc").group()` 
    `re.match(r".*ver", "hover abc").group()`
    匹配的位置:前面和后面的字符不全是w匹配成功,反过来理解,如果的前面和后面都是w,则不匹配
    
    匹配大陆手机号
    re.match("^1[34578]d{9}$", "17611105750")
    
    • 匹配分组
    字符 功能
    | 匹配左右任意一个表达式(左或右)
    (ab) 将括号中字符作为一个分组
    um 引用分组num匹配到的字符串
    (?P<name>) 分组起别名
    (?P=name) 引用别名为name分组匹配到的字符串
    # 匹配1-100之间的数字:
    ret = re.match(‘[1-9]d?$|0$|100$',“8")
    print(ret.group())
    
    ret = re.match('[1-9]?d$|100$','8')
    

    分组就是用一对圆括号“()”括起来的正则表达式,匹配出的内容就表示一个分组。
    从正则表达式的左边开始看,看到的第一个左括号“(”表示第一个分组,第二个表示第二个分组,依次类推,需要注意的是,有一个隐含的全局分组(0),就是整个正则表达式。
    分完组以后,要想获得某个分组的内容,直接使用group(num)和groups()函数提取

    ret = re.match("w{4,20}@163.com", "test@163.com")
    ret = re.match("w{4,20}@(163|126|qq).com", "test@126.com")
    ret = re.match("w{4,20}@(163|126|qq).com", "test@qq.com")
    ret = re.match("([^-]*)-(d+)","010-12345678")
    ret.group()
    #'010-12345678'
    ret.group(1)
    #'010'
    ret.group(2)
    #'12345678'
    ret.groups()
    
    ret = re.match(r"<(w*)><(w*)>.*</2></1>", "<html><h1>www.sxt.cn</h1></html>")
    ret.group()
    
    ret = re.match(r"<(w*)><(w*)>.*</2></1>", "<html><h1>www.sxt.cn</h2></html>")
    ret.group()
    
    ret = re.match(r"<(?P<name1>w*)><(?P<name2>w*)>.*</(?P=name2)></(?P=name1)>", "<html><h1>www.sxt.cn</h1></html>")
    ret.group()
    
    ret = re.match(r"<(?P<name1>w*)><(?P<name2>w*)>.*</(?P=name2)></(?P=name1)>", "<html><h1>www.sxt.cn</h2></html>")
    ret.group()
    # 注意: (?P<name>) 和 (?P=name) 中的字⺟p⼤写
    
    • re模块的其他函数
    1. match: re.match(pattern,string,flags=0),从头开始匹配,匹配成功返回一个匹配对象,该匹配对象有group,start,end,span,groups等方法,用于返回匹配内容,匹配不成功则返回None,不成功时,没有group方法。flags是编译标志位,用于修改正则表达式的匹配方式,如:是否匹配大小写,是否多行匹配等。
      flags的实参有以下几种:
      1.1. re.I 使匹配对大小写不敏感。
      1.2. re.L 做本地化识别(locale-aware)匹配.
      1.3. re.M 多行匹配,影响^和$.
      1.4. re.S 使.匹配包括换行在内的所有字符
      1.5. re.U 根据Unicode字符集解析字符,影响w,W,,B
      1.6. re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更灵活。
      匹配成功返回的对象的方法有以下几种:
      1.7. group(n=0) 不传参数,默认是0,返回re整体匹配的字符串,可以一次输入多个组号,对应组的组号。
      1.8. group(n,m) 返回组号为n,m所匹配的字符串,如果组号不存在,会报错。
      1.9. groups() 返回一个元组,元组中元素是正则表达式中每个小组匹配到的字符串。通常groups不加参数。
      1.10. start() 返回匹配开始的位置。
      1.11. end() 返回匹配结束的位置。
      1.12. span() 返回一个元组包含匹配(开始,结束)的位置。
      re.match('com','comww.runcomoob').group()
      re.match('com','Comww.runcomoob',re.I).group()
    2. search re.search(pattern,string,flags=0)搜索符合特征的第一个字符串,匹配成功返回一个匹配对象,该匹配对象有group,start,end,span,groups等方法,用于返回匹配内容,匹配不成功则返回None,不成功时,没有group方法:
      ret = re.search(r"d+", "阅读次数为 9999")
      ret.group()
    3. findall 找出所有符合特征的字符串,并返回一个列表,不需要用group方法即可返回列表,finall优先返回组里面的内容,如果要取消,则在组前面加上?:;如果pattern有超过1个分组,则列表的元素是一个包含所有分组匹配内容的元组:
      In [32]: re.findall(r'(d{0,4})','xyz024abc123')
      Out[32]: ['', '', '', '024', '', '', '', '123', '']
      In [33]: re.findall(r'(d{0,4})(w{0,3})(d)','xyz024abc123')
      Out[33]: [('', 'xyz', '0'), ('24', 'abc', '1'), ('2', '', '3')]
    4. sub re.sub(pattern,repl,string,max=0)将匹配到的数据进⾏替换,返回替换后的字符串,max指最大替换多少次,默认0是全部替换。:
      ret = re.sub(r"d+", '998', "python = 997")
      ret = re.sub(r'g.t','have','I get apple, I got orange, I gut banana.',2)
    5. split:re.split(pattern,string),根据匹配进⾏切割字符串,并返回⼀个列表:
      ret = re.split(r":| ","info:xiaoZhang 33 shandong")
      p = re.compile('d')
      In [38]: p.split('one1two2three3four4')
      Out[38]: ['one', 'two', 'three', 'four', '']
    6. compile: re.compile(strPattern[,flag]) 如果要多次调用规则,则使用compile方法,先将规则编译好。
      regex = re.compile(r'w*oow*'),regex.findall('helloo, good')
    7. finditer(pattern,string),返回的是包含匹配对象的迭代器。如果要获得匹配内容,得遍历迭代器得到匹配对象,再调用匹配对象的group方法。
      re.finditer(r'd+','12drum44ers druming,11,drun12,13,14')
    • 贪婪和非贪婪

    Python⾥正则表达式数量词( "*","?","+","{m,n}" )默认是贪婪的, 总是尝试匹配尽可能多的字符

    s = "number is 123456789"
    ret = re.match(r"(.+)(d)",s)
    print(ret.group(1))
    

    ⾮贪婪则相反, 总是尝试匹配尽可能少的字符:
    在"*","?","+","{m,n}"后⾯加上? , 使贪婪变成⾮贪婪.
    result = re.match(r"aa(d+)","aa2343ddd").group(1)
    '2343'
    result = re.match(r"aa(d+?)","aa2343ddd").group(1)
    '2'

    贪婪和非贪婪的到的结果也有可能是一样的
    result = re.match(r"aa(d+)ddd","aa2343ddd").group(1)
    '2343'
    result = re.match(r"aa(d+?)ddd","aa2343ddd").group(1)
    '2343'

    作业:

    import re
    # 1. 判断字符串是否是全部小写
    s1 = 'qwerty123A'
    result1 = re.match('^[a-z]*$',s1)
    if result1:
        print(result1.group())
    else:
        print('不是全部小写,无法匹配')
    
    # 2. 匹配由数字/26个英文字母组成的字符串
    p2= '[0-9a-zA-Z]*'
    s2 ='1323abcABC_xyz'
    result2 = re.match(p2,s2)
    print(result2.group())
    
    # 3. 匹配长度为8-10的用户密码(以字母开头/数字/下划线)
    p3 = '^[a-zA-Z]w{7,9}$'
    s3 = 'abc1323_xy'
    result3 = re.match(p3,s3)
    print(result3.group())
    
    # 4. 电子邮箱验证
    p4 = r'w{4,20}@(163|126|qq).com'
    s4 = '3768094lan@163.com'
    result4 = re.match(p4,s4)
    if result4:
        print(result4.group())
    
    # 5. 简单的身份证号验证
    p5 = r'[1-6]d{5}(18|19|20)d{2}(0[1-9]|1[012])(0[1-9]|[12]d|3[01])d{3}(d$|X$)'
    s5 = '36078219880631032X'
    
    result5 = re.match(p5,s5)
    if result5:
        print(result5.group())
    else:
        print('不是身份证号码')
    
    
    # 6. 提取并捕获html标签内容
    p6 = r'<(?P<html>w*)><(?P<h1>w*)>(.*)</(?P=h1)></(?P=html)>'
    s6 = '<html><h1>我爱你</h1></html>'
    result6 = re.match(p6,s6)
    if result6:
        print(result6.group(3))
    else:
        print('不正确')
    
  • 相关阅读:
    IP地址分类整理
    PHP
    [转载]数组的全排列问题
    使用 Homebrew 安装 Git
    Homebrew简介及安装
    iOS开发~CocoaPods使用详细说明
    关于目前自己iOS项目使用的第三方开源库
    IOS 时间格式 时间转换 大总结
    Xcode磁盘空间大清理
    Swift百万线程攻破单例(Singleton)模式
  • 原文地址:https://www.cnblogs.com/lanxing0422/p/pythonday6.html
Copyright © 2011-2022 走看看