• (常用)re模块


    re模块(正则)
    #re:一些带有特殊含义的符号或者符号的组合
    #为什么要用re:一堆字符串中找到你所需要的内容,过滤规则是什么样,通过re模块功能来告诉计算机你的过滤规则
    #应用:在爬虫中最为常用;使用爬虫时有其他模块可以导入帮助clear数据,正则也可用于其他方面
    #原理:re模块的内部实现 不是python 而是调用了c库
    import re
    print(re.findall('w','ab 12+- *&_'))
    print(re.findall('W','ab 12+- *&_'))
    print(re.findall('s','ab 1 2 +- *&_'))
    print(re.findall('S','ab 1 2 +- *&_'))
    print(re.findall('d','ab 1 2 +- *&_'))
    print(re.findall('D','ab 1 2 +- *&_'))
    print(re.findall('w_sb','egon alex_sb123123wxx_sb,lxx_sb'))
    print(re.findall('Aalex','abcalex is salexb'))
    print(re.findall('Aalex','alex is salexb'))
    print(re.findall('^alex','alex is salexb'))
    print(re.findall('sb','alexsb is sbalexbsb'))
    print(re.findall('sb$','alexsb is sbalexbsb'))
    print(re.findall('^ebn$','ebn1')) #^ebn$ 筛出的就是ebn(以ebn开头,以ebn结尾)
    print(re.findall('a c','a c a c a1c'))
    为制表符,在不同平台表示不同的空个数
    A  ^     #使用^
      $     #使用$
    # 重复匹配:
    #.   ?   *   +  {m,n}  .*  .*?  {m}
    1、.:代表除了换行符外任意一个字符 
    . 除了换行符之外的任意一个字符, 如果想不除换行符,后加re.DOTALL
    print(re.findall('a.c','abc a1c aAc aaaaaca c'))
    print(re.findall('a.c','abc a1c aAc aaaaaca c',re.DOTALL))
    2、:代表左边那一个字符重复0次或1次 默认贪婪(能匹配1次绝不匹配0次)
    ?不能单独使用
    print(re.findall('ab?','a ab abb abbb abbbb abbbb'))
    3、*:代表左边那一个字符出现0次或无穷次 默认贪婪(能匹配无穷次绝不匹0次)
    print(re.findall('ab*','a ab abb abbb abbbb abbbb a1bbbbbbb'))
    4、+ :代表左边那一个字符出现1次或无穷次 默认贪婪(能匹配无穷次绝不匹配1次)
    print(re.findall('ab+','a ab abb abbb abbbb abbbb a1bbbbbbb'))
    5、{m,n}:代表左边那一个字符出现m次到n次  默认贪婪(能匹配n次绝不匹配m次)
    print(re.findall('ab?','a ab abb abbb abbbb abbbb'))
    print(re.findall('ab{0,1}','a ab abb abbb abbbb abbbb'))
    print(re.findall('ab*','a ab abb abbb abbbb abbbb a1bbbbbbb'))
    print(re.findall('ab{0,}','a ab abb abbb abbbb abbbb a1bbbbbbb'))
    print(re.findall('ab+','a ab abb abbb abbbb abbbb a1bbbbbbb'))
    print(re.findall('ab{1,}','a ab abb abbb abbbb abbbb a1bbbbbbb'))
    print(re.findall('ab{1,3}','a ab abb abbb abbbb abbbb a1bbbbbbb'))
    6、.*:匹配任意长度,任意的字符=====》贪婪
    print(re.findall('a.*c','ac a123c aaaac a *123)()c asdfasfdsadf'))
    7、.*?多少次到多少次(贪婪)+ ?=非贪婪
    print(re.findall('a.*?c','a123c456c'))
    ():分组
    print(re.findall('(alex)_sb','alex_sb asdfsafdafdaalex_sb'))
    print(re.findall(
        'href="(.*?)"',
        '<li><a id="blog_nav_sitehome" class="menu" href="http://www.cnblogs.com/">博客园</a></li>')
    )
    []:匹配一个指定范围内的字符(这一个字符来自于括号内定义的)
    [] 内写什么就是其单独的意义, 可写0-9 a-zA-Z
    print(re.findall('a[0-9][0-9]c','a1c a+c a2c a9c a11c a-c acc aAc'))
    当-需要被当中普通符号匹配时,只能放到[]的最左边或最 右边
    a-b有特别的意思,所以如果想让-表示它本身,要将其放在最左或最右
    print(re.findall('a[-+*]c','a1c a+c a2c a9c a*c a11c a-c acc aAc'))
    print(re.findall('a[a-zA-Z]c','a1c a+c a2c a9c a*c a11c a-c acc aAc'))
    []内的^代表取反的意思 (^在[]中表示取反)
    print(re.findall('a[^a-zA-Z]c','a c a1c a+c a2c a9c a*c a11c a-c acc aAc'))
    print(re.findall('a[^0-9]c','a c a1c a+c a2c a9c a*c a11c a-c acc aAc'))
    print(re.findall('([a-z]+)_sb','egon alex_sb123123wxxxxxxxxxxxxx_sb,lxx_sb'))
    | :或者
    print(re.findall('compan(ies|y)','Too many companies have gone bankrupt, and the next one is my company'))
    (?:   ):代表取匹配成功的所有内容,而不仅仅只是括号内的内容 ((?:   )表示匹配的结果都要,不单单要()内的
    print(re.findall('compan(?:ies|y)','Too many companies have gone bankrupt, and the next one is my company'))
    print(re.findall('alex|sb','alex sb sadfsadfasdfegon alex sb egon'))
    re模块的其他方法:
    print(re.findall('alex|sb','123123 alex sb sadfsadfasdfegon alex sb egon'))
    print(re.search('alex|sb','123213 alex sb sadfsadfasdfegon alex sb egon').group())
    print(re.search('^alex','123213 alex sb sadfsadfasdfegon alex sb egon'))
    print(re.search('^alex','alex sb sadfsadfasdfegon alex sb egon').group())
    re.search, 取第一个结果,若没有返回None;若想让结果直接显示后加group();返回None时用group()会报错
    re.match 相当于^版本的search
    print(re.match('alex','alex sb sadfsadfasdfegon alex sb egon').group())
    print(re.match('alex','123213 alex sb sadfsadfasdfegon alex sb egon'))
    re.match 相当于^版本的search
    re.split与split相比,内部可以使用正则表达式
    info='a:b:c:d'
    print(info.split(':'))
    print(re.split(':',info))
    info=r'get :a.txt3333/rwx'
    print(re.split('[ :\/]',info))
    re.sub 与replace相比,内部可以使用正则表达式
    print('egon is beutifull egon'.replace('egon','EGON',1))
    print(re.sub('(.*?)(egon)(.*?)(egon)(.*?)',r'123EGON5','123 egon is beutifull egon 123'))
    print(re.sub('(lqz)(.*?)(SB)',r'321',r'lqz is SB'))
    print(re.sub('([a-zA-Z]+)([^a-zA-Z]+)([a-zA-Z]+)([^a-zA-Z]+)([a-zA-Z]+)',r'52341',r'lqzzzz123+ is SB'))
    太常用的表达式可以做成
    pattern=re.compile('alex')
    print(pattern.findall('alex is alex alex'))
    print(pattern.findall('alexasdfsadfsadfasdfasdfasfd is alex alex'))
     
    断言
     正则表达式中的断言,作为高级应用出现,倒不是因为它有多难,而是概念比较抽象,不容易理解而已。
     如果不用断言,以往用过的那些表达式,仅仅能获取到有规律的字符串,而不能获取无规律的字符串。
    举个例子,比如html源码中有<title>xxx</title>标签,用以前的知识,我们只能确定源码中的<title>和</title>是固定不变的。因此,如果想获取页面标题(xxx),充其量只能写一个类似于这样的表达式:<title>.*</title>,而这样写匹配出来的是完整的<title>xxx</title>标签,并不是单纯的页面标题xxx。
           想解决以上问题,就要用到断言知识。
           在讲断言之前,读者应该先了解分组,这有助于理解断言。
           分组在正则中用()表示,根据小菜理解,分组的作用有两个:
           n  将某些规律看成是一组,然后进行组级别的重复,可以得到意想不到的效果。
           n  分组之后,可以通过后向引用简化表达式。
           先来看第一个作用,对于IP地址的匹配,简单的可以写为如下形式:
           d{1,3}.d{1,3}.d{1,3}.d{1,3}
           但仔细观察,我们可以发现一定的规律,可以把.d{1,3}看成一个整体,也就是把他们看成一组,再把这个组重复3次即可。表达式如下:
           d{1,3}(.d{1,3}){3}
    这样一看,就比较简洁了。
    再来看第二个作用,就拿匹配<title>xxx</title>标签来说,简单的正则可以这样写:
           <title>.*</title>
           可以看出,上边表达式中有两个title,完全一样,其实可以通过分组简写。表达式如下:
           <(title)>.*</1>
           这个例子实际上就是反向引用的实际应用对于分组而言,整个表达式永远算作第0组,在本例中,第0组是<(title)>.*</1>,然后从左到右,依次为分组编号,因此,(title)是第1组
           用1这种语法,可以引用某组的文本内容,1当然就是引用第1组的文本内容了,这样一来,就可以简化正则表达式,只写一次title,把它放在组里,然后在后边引用即可。
           以此为启发,我们可不可以简化刚刚的IP地址正则表达式呢?原来的表达式为d{1,3}(.d{1,3}){3},里边的d{1,3}重复了两次,如果利用后向引用简化,表达式如下:
           (d{1,3})(.1){3}
           简单的解释下,把d{1,3}放在一组里,表示为(d{1,3}),它是第1组,(.1)是第2组,在第2组里通过1语法,后向引用了第1组的文本内容。
           经过实际测试,会发现这样写是错误的,为什么呢?
           小菜一直在强调,后向引用,引用的仅仅是文本内容,而不是正则表达式!
           也就是说,组中的内容一旦匹配成功,后向引用,引用的就是匹配成功后的内容,引用的是结果,而不是表达式。
           因此,(d{1,3})(.1){3}这个表达式实际上匹配的是四个数都相同的IP地址,比如:123.123.123.123。
           至此,读者已经掌握了传说中的后向引用,就这么简单。
           接下来说说什么是断言。
           所谓断言,就是指明某个字符串前边或者后边,将会出现满足某种规律的字符串。
           就拿文章开篇的例子来说,我们想要的是xxx,它没有规律,但是它前边肯定会有<title>,后边肯定会有</title>,这就足够了。
           想指定xxx前肯定会出现<title>,就用正后发断言,表达式:(?<=<title>).*
           向指定xxx后边肯定会出现</title>,就用正先行断言,表达式:.*(?=</title>)
           两个加在一起,就是(?<=<title>).*(?=</title>)
           这样就能匹配到xxx。
         
           其实掌握了规律,就很简单了,无论是先行还是后发,都是相对于xxx而言的,也就是相对于目标字符串而言。
           假如目标字符串后边有条件,可以理解为目标字符串在前,就用先行断言,放在目标字符串之后。
           假如目标字符串前边有条件,可以理解为目标字符串在后,就用后发断言,放在目标字符串之前。
           假如指定满足某个条件,就是正。
           假如指定不满足某个条件,就是负。
           断言只是条件,帮你找到真正需要的字符串,本身并不会匹配!
     
        

    (?=X )
    零宽度正先行断言。仅当子表达式 X 在 此位置的右侧匹配时才继续匹配。例如,/w+(?=/d) 与后跟数字的单词匹配,而不与该数字匹配。此构造不会回溯。
    (?!X)
    零宽度负先行断言。仅当子表达式 X 不在 此位置的右侧匹配时才继续匹配。例如,例如,/w+(?!/d) 与后不跟数字的单词匹配,而不与该数字匹配 。
    (?<=X)
    零宽度正后发断言。仅当子表达式 X 在 此位置的左侧匹配时才继续匹配。例如,(?<=19)99 与跟在 19 后面的 99 的实例匹配。此构造不会回溯。
    (?<!X)
    零宽度负后发断言。仅当子表达式 X 不在此位置的左侧匹配时才继续匹配。例如,(?<!19)99 与不跟在 19 后面的 99 的实例匹配
  • 相关阅读:
    第二次编程作业总结
    structs get 方法乱码问题
    网址记录
    尸体解剖报告
    最后冲刺
    回答自己的提问——对自己最大的反馈
    构建之法13-17章读后感
    典型场景
    对其他各团队的评价
    用户调研
  • 原文地址:https://www.cnblogs.com/3sss-ss-s/p/9475200.html
Copyright © 2020-2023  润新知