liangzhiwen

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
正则表达式

应用场景

- 特定规律字符串的查找,切割,替换
- 邮箱格式:URl,IP地址等的校验
- 爬虫项目中,特定内容的提取

使用原则

- 只要使用字符串等函数能解决的问题,就不要使用正则
- 正则的效率比较低,同时会降低代码的可读性
- 世界上最难理解的三样东西,医生的处方,道士的神符,码农的正则
- 提醒: 正则是用来写的,不是用来读的,在不指定功能的情况下,不要试图阅读别人的正则

基本使用

- 说明: 正则不是我们写的,python中正则的解析通过 re模块完成
- 相关函数;
  - match:  从开头进行匹配,匹配到就返回正则结果对象,没有返回None
  - sertch:从任意位置匹配,功能同上
        import re
        
        # m = re.match("abc","adask;jabcsdaj1")
        m1 = re.match("abc","abcsk;jadasdaj1")
        # print(m)  # 没有找到返回None
        # print(m1)# 找到正则匹配结果对象,
        if m1:
            print(m1.group()) # 返回匹配的内容
            print(m1.span())  #返回匹配的内容位置
        """
        # match 从开头查找
        # """
        #
        s = re.search("abc","adask;jabcsdaj1d")
        # print(s)
        
  - findall :   有就返回所有匹配对象,组成列表,没有返回空列表
        # 匹配所有内容,找到返回所有匹配的内容列表,
        # 没有找到返回空列表
        f = re.findall("abcd","adask;jabcsdabcaj1")
        # print(f)
  - compile : 生成正则表达式对象
        # 先生成正则表达式对象
        c = re.compile("hello")
        # print(type(c))
        
        # 从开头匹配
        i = c.match("sad;asdawafhelloasdaw;asdw")
        print(i)
        
        # 从任意位置匹配
        se = c.search("sasdwdhelloasd;asdas")
        print(se)
        
        # 匹配所有内容
        fi = c.findall("helloadad;asdahello;asdfkajehelloasda")
        print(fi)
    - 说明 ,此方式更加灵活,将正则匹配分为两步完成(先生成正则对象,然后需要时进行验证)

正则规则

- 单个字符
  -     "普通字符:简单来说就是一对一的完全匹配"
        []:中间的任意一个字符
          [a-z]: a~z之间的任意字符(所有的小写字母) 
          [A-Za-z]:匹配所有的字母,多个连续的片段中间不能有任何多余的字符
          [^0-9]: 匹配 除了0-9 以外的所有字符
        . (点): 匹配除 \n 以外的任意字符
        自行测试:
        \d  :数字字符 ,相当于[0-9]
        \D  :非数字字符 ,相当于[^0-9]
        \w  :匹配字(数字,字母,下划线,汉字)
        \W  :匹配非字,(\w相反的内容)
        \s  :所有的空白字符
        \S  :所有的非空白字符
        \b  :词边界 (开头。结尾,空格,标点等)
        \B  :非词边界(\b相反的内容)
- 次数限定:
  -     # 指定字符任意次
        # f = re.findall("ab*c","sabfabibabuabcbbavadba")
        # 指定字符至少一次
        print(re.findall("ab+c","sdhasjhfsljabcasofjia"))
        # 指定字符最多出现一次,有或者没有都可以
        print(re.findall("ab?c","sdhasjhfsljacasofjia"))
        # #指定字符出现指定次数
        print(re.findall("ab{3}c","sdhasjhabbbcfsljacasofjia"))
        # 指定字符 出现次数的范围
        print(re.findall("ab{1,3}c","sdhabbbcsjhabcfslfjia"))
        # 指定字符,至多出现多少次
        # print(re.findall("ab{0,5}c","sacaabcabcabcabia"))
        # 指定字符,至少出现多少次
        print(re.findall("ab{3,}c","sdhabbchfsljaca"))
        *:前面的字符出现任意次
        +:至少一次
        ?:最多一次
        {m,n}:m <= 次数 <= n
        {m,}:至少m次
        {,n}:至多n次
        {m}:指定m次
        
- 边界限定
  - ^ : 以指定内容从开头进行匹配
  - $ : 以指定内容从结尾进行匹配-p
        import re
        # ^ : 以指定内容从开头进行匹配
        print( re.findall("^hello","adahelloaawhellowadhello"))
        # $ : 以指定内容从结尾进行匹配
        print( re.findall("hello$","adahelloaawhellowadhellxo"))
        
- 优先级控制
  - |  表示或,它拥有最低的优先级
  - ()  表示一个整体,可以明确的指定结合性/优先级
        import re
        print(re.findall("a(hello|world)c","hiahellociaworldc")
- 分组匹配
      c = re.compile(r"(\d+)([a-z]+)(\d+)")
      s = c.search("sadasdaf454as6aa46sd4w")
      
      """
      完整匹配结果
      print(s.group())
      ↑↓等价
      print(s.group(0))  
      """
      # 第几个()匹配的结果
      print(s.group(1), s.span(1))
      print(s.group(2), s.span(2))
      print(s.group(3), s.span(3))
  - 示例2:
        import re
        
        # 固定匹配
        # c = re.compile(r'<a>\w+</a>')
        
        # \1表示前面第一个()匹配的内容
        # c = re.compile(r'<([a-z]+)><([a-z]+)>\w+</\2></\1>')
        
        # 给分组()起名字
        c = re.compile(r'<(?P<goudan>[a-z]+)><(?P<dahua>[a-z]+)>\w+</(?P=dahua)></(?P=goudan)>')
        
        s = c.search('<div><a>百度一下</a></div>')
        
        if s:
        	print(s.group())
    
- 贪婪匹配
  - 贪婪 : 最大限度的匹配,正则的匹配默认就是贪婪。
  - 非贪婪: 只要满足条件, 能少匹配就少匹配。? 经常用于取消贪婪
        import  re
        # ? :取消任意多次的贪婪匹配
        # c = re.compile(r"a.*?b")
        # s = c.search("wwa0a0dwaadavab")
        # ?:取消至少一次的贪婪匹配
        c = re.compile(r"a.+?b")
        s = c.search("wwa0abwaadavab")
        if s:
            print(s.group())
        
- 匹配模式
  - 说明: 匹配模式就是匹配的原则进行模式的修正
      import re
      """
      flags: 标志位,用于控制正则表达式的匹配方式,值如下:               
      re.I   忽略大小写(常用)                             
      re.L   做本地户识别                                
      re.M   多行匹配,影响^和$(常用)                        
      re.S   是. 匹配包括换行符 \n 在内的所有字符(常用)             
      re.U   根据Unicode字符集解析字符,影响 r"\w \W \b \B"(常用)
      re.X   使我们以更灵活的格式理解正则表达式 (常用)                
      """
      # 忽略大小写re.I
      s = re.search(r'hello', 'HELLO world', re.I)
      
      # 正则默认是单行匹配,使用 re.M 可以进行多行匹配
      s = re.search(r'^hello', 'sdhasdh\nhello world', re.M)
      
      # 使.匹配任意字符,作为单行处理,忽略\n
      # string = '<div>hello</div>'
      string = '''<div>
      hello
      </div>'''
      s = re.search(r'<div>.*?</div>', string, re.S)
      
      if s:
          print(s.group())
      
- findall
      import re
      
      # 没有(),结果集中保存完整匹配的内容
      # f = re.findall('abc', 'abcdasabcakdjklasjabc')
      # 与上面的情况等价
      # f = re.findall('(abc)', 'abcdasabcakdjklasjabc')
      # 按照正则进行完整匹配,但是结果集只显示分组内容
      # f = re.findall('qq(abc)ww', 'ahdakqqabcwwhsad')
      # 按照正则进行完整匹配,但是结果集中的元素时分组信息组成的元组
      # f = re.findall('qq(abc)(ww)', 'ahdakqqabcwwhsaqqabcwwd')
      # 满足上面所有的规律
      # f = re.findall('(qq(abc)(ww))', 'ahdakqqabcwwhsaqqabcwwd')
      # 匹配:'a(hello)c' 或 'a(world)c'
      # f = re.findall('a(hello|world)c', 'sadahellocshdjaworldcsd')
      f = re.findall('(a(hello|world)c)', 'sadahellocshdjaworldcsd')
      
      print(f)
- split
      import re
      
      c = re.compile(r'\d')
      
      s = '正则其实不难1但是学完之后2发现写不出来3是这样吧'
      
      # 按照正则规律进行切割,可以指定切割次数
      ret = c.split(s, 1)
      
      print(ret)
- sub
      import re
      
      '''
      c = re.compile(r'\d')
      
      # 使用特点内容替换正则匹配到的内容,可以指定替换次数
      ret = c.sub(' ', 'how1are2you', 2)
      
      print(ret)
      '''
      
      def double(s):
      	# print(s)
        	return str(int(s.group()) * 2)   
      
      # 可以人为的干预正则替换的过程
      # 因此需要传递一个处理的(匿名)函数
      ret = re.sub(r'\d', double, 'how1are2you')
      print(ret)
      
- 转义问题
        import re
      
        # 匹配所有正则语法中涉及的字符都需要转义
      
        '''
        # python: \\\\d     \\\d   r'\\d'
        # re:    \\d        \\d     \\d
        # 匹配:   \d          \d      \d
        # c = re.compile('\\\\d')
        # c = re.compile('\\\d')
        # 推荐使用,否则你需要多写好多\
        c = re.compile(r'\\d')
      
        s = c.search('\d')
      
        if s:
            print(s.group())
        '''
      
        '''
        c = re.compile(r'\\b')
      
        # 在匹配的字符串中有特殊意义的字符也需要进行转义
        # 若不想转义最好前面添加字符'r'
        s = c.search(r'\b')
      
        if s:
            print(s.group())
        '''
      
        # 了解
        # c = re.compile(r'\bhello')
        # 单独匹配边界,findall保存的结果全都是空白
        c = re.compile(r'\b')
      
        f = c.findall('hello,sdjaks')
      
        print(f)  
  1. 使用正则时,python字符串有特殊意义的字符最好转义
  2. 要匹配在正则语法中有特殊函数的字符,都需要进行转义
  3. 字符串前添加'r',可以使其变为原始字符,不要考虑转义问题

 

posted on 2018-09-10 11:02  liangzhiwen  阅读(165)  评论(0编辑  收藏  举报