• 正则表达式以及python的re模块介绍


    正则表达式

    字符串是编程时涉及到的最多的一种数据结构,对字符串进行操作的需求几乎无处不在。比如判断一个字符串是否是合法的Email地址,虽然可以编程提取@前后的子串,再分别判断是否是单词和域名,但这样做不但麻烦,而且代码难以复用。

    正则表达式是一种用来匹配字符串的强有力的武器。它的设计思想是用一种描述性的语言来给字符串定义一个规则,凡是符合规则的字符串,我们就认为它“匹配”了,否则,该字符串就是不合法的。

    所以我们判断一个字符串是否是合法的Email的方法是:

    1. 创建一个匹配Email的正则表达式;
    2. 用该正则表达式去匹配用户的输入来判断是否合法。

    因为正则表达式也是用字符串表示的,所以,我们要首先了解如何用字符来描述字符。

    • 基础

      \d 可以匹配一个数字
      \w 可以匹配一个字母或数字
      \s 匹配任意的空白字符。所谓空白字符,包括空格、tab键(制表符)、回车符、换行符等等。
      . 可以匹配匹配任意单个字符
      * 表示任意个字符(0个或多个)
      + 表示至少一个字符
      ? 表示0个或1个字符
      {n}表示n个字符
      {n,m}表示n~m个字符
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

      例子:

      '00\d'可以匹配'007'
      '\w\w\d'可以匹配'py3'
      'py.'可以匹配'pyc'、'pyo'、'py!'
      
      \d{3}\s+\d{3,8} :\d{3}表示匹配3个数字,\s可以匹配一个空格,所以\s+表示至少有一个空格
      
      • 1
      • 2
      • 3
      • 4
      • 5

      如果要匹配’010-12345’这样的号码呢?由于’-'是特殊字符,在正则表达式中,要用\转义,所以,正则是

      \d{3}\-\d{3,8}
      
      • 1

      正则表达式内部:如果有特殊字符也是需要手动转义的

      • 进阶

        要做更精确地匹配,可以用[]表示范围,[]内是所有可选项

        a-b :表示从a~b的所有字符 
        [0-9a-zA-Z\_]  可以匹配一个数字、字母或者下划线
        [0-9a-zA-Z\_]+ 可以匹配至少由一个数字、字母或者下划线组成的字符串,比如'a100','0_Z'
        [a-zA-Z][0-9a-zA-Z\_]可以匹配由字母开头,后接任意个由一个数字、字母或者下划线组成的字符串
        [a-zA-Z][0-9a-z]{0, 19}更精确地限制了变量的长度是1-20个字符(前面1个字符+后面最多19个字符)
        
        A|B  表示:A或B,所以(P|p)ython可以匹配'Python'或者'python'。
        ^    表示行的开头,^\d表示必须以数字开头。
        $    表示行的结束,\d$表示必须以数字结束。
        ^py$ 表示结果只能是py
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10

    字符转义的理解

    在任意编程语言中,定义的一个用户的一个字符串,在被加载的时候不是不变的,比如s = “\n"会被解析成为一个换号,但是当我们需要输出”\n"时,我们要这样写s = "\\n",也就是在前面再加一个"\",表示后面的这个斜杠是一个普通斜杠,表示它不用被转义。简单点说,一个字符串默认有可能会被解析成一个特殊的含义(换行),但是我们不想要这样,所以需要自己去转义这个特殊字符,使得得到我们想要的结果。一般情况下,都是使用\来转义字符。

    也就是说,转义特殊字符需要手动在前面加\,python中很方便

    • 正则表达式

      在写正则表达式时,对于一些特殊字符的匹配也是需要转义的。比如想要匹配一些特殊的字符,比如-,-在正则表达式中就是个特殊字符,用来表示一个范围,如果要匹配"1-1"这样的情况,正则表达式是"\d\-\d",而不是"\d-\d"

    • python

      在python中可以直接使用re.match函数去匹配正则表达式

      但是,py中定义了一个字符串,很有可能被python给转义成其他东西了,所以需要转义,py有两种方法

      • 方法1:使用只读参数r,强制不转义

        s = r'ABC\-001'
        
        • 1
      • 方法2:re.escape

        转义特殊字符需要手动在前面加\,python中有现成的api,可以将给定字符串中的所有特殊字符前面都加上\,也就是re.escape()函数

        pattern1 = re.escape("a*b") # 相当于pattern1 = a\*b
        pattern2 = "a\*b" # pattern2和pattern1一样
        
        • 1
        • 2
    • 例子

      import re
      
      # 想要匹配的表达式是'a\-',但是py把斜杠转义了,导致pattern从'a\\-'变成了'a\-',导致匹配到'a-'也成功了
      pattern = 'a\\-'
      input = 'a-'
      res = re.match(pattern, input)  # 匹配成功
      print(res)
      
      # 正确写法
      pattern = r'a\\-'  # 只读,不解析
      input = 'a\-'
      res = re.match(pattern, input)  # 成功
      print(res)
      
      pattern = re.escape('a\\-')  # 调用api自动加\
      input = 'a\-'
      res = re.match(pattern, input)  # 成功
      print(res)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18

    re.match函数

    match()方法判断是否匹配,如果匹配成功,返回一个Match对象,否则返回None

    例子

    import re
    
    pattern = r".a."
    url = "Aa9"
    
    if re.match(pattern, url):
        print("匹配成功!") 
    else:
        print("匹配失败!")
    # 输出: 匹配成功
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    匹配邮箱

    # 匹配邮箱
    pattern = r'^[a-zA-Z0-9\.]+@[a-zA-Z0-9\.]+\.com$'
    pattern = r'^[\w\.]+@[\w\.]+\.com$' # 简写
    
    print(re.match(pattern,'someone@gmail.com'))
    print(re.match(pattern,'bill.gates@microsoft.com'))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 扩展

      可以提取出带名字的Email地址:

      tom@voyager.org => Tom Paris

      bob@example.com => bob

      import re
      
      def name_of_email(addr):
          re_name_of_email = re.compile(r'?\s?([0-9a-zA-Z]+)*@[0-9a-zA-Z]+.org')
          m = re_name_of_email.match(addr)
          print(m.groups())
          if m.group(1):
              return m.group(1).strip()
          else:
              return m.group(2)
      
      # 测试:
      assert name_of_email(' tom@voyager.org') == 'Tom Paris'
      assert name_of_email('tom@voyager.org') == 'tom'print('ok')
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14

    re.escape函数

    reference:https://www.python100.com/html/79913.html

    在Python的正则表达式(re)模块中,re.escape函数是一个非常有用的工具,它用于将一个字符串中的特殊字符转义成正则表达式中的普通字符。在使用正则表达式进行字符串的匹配时,如果字符串中包含了正则表达式的特殊字符,那么就需要使用re.escape函数来对这些特殊字符进行转义,让它们变成普通字符,以保证匹配的准确性。

    简单点说,re.escape函数就是将字符串中的所有特殊字符前面全部加上\

    语法如下

    re.escape(string)
    
    • 1

    其中,string是需要进行转义的字符串参数。

    例子:

    import re
    
    pattern1 = re.escape("a*b") # 结果是pattern1 = a\*b
    pattern2 = "a\*b" # pattern2和pattern1一样
    str = "a*b"
    
    if re.match(pattern1, str) and re.match(pattern2, str):
        print("两种方式都可以匹配!")
    else:
        print("匹配失败!")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    切分字符串

    用正则表达式切分字符串比用固定的字符更灵活,请看正常的切分代码:

    >>> 'a b   c'.split(' ')
    ['a', 'b', '', '', 'c']
    
    • 1
    • 2

    嗯,无法识别连续的空格,用正则表达式试试:

    >>> re.split(r'\s+', 'a b   c')
    ['a', 'b', 'c']
    
    • 1
    • 2

    无论多少个空格都可以正常分割。加入,试试:

    >>> re.split(r'[\s\,]+', 'a,b, c  d')
    ['a', 'b', 'c', 'd']
    
    • 1
    • 2

    再加入;试试:

    >>> re.split(r'[\s\,\;]+', 'a,b;; c  d')
    ['a', 'b', 'c', 'd']
    
    • 1
    • 2

    分组

    除了简单地判断是否匹配之外,正则表达式还有提取子串的强大功能。用()表示的就是要提取的分组(Group)。比如:

    ^(\d{3})-(\d{3,8})$分别定义了两个组,可以直接从匹配的字符串中提取出区号和本地号码:

    >>> m = re.match(r'^(\d{3})-(\d{3,8})$', '010-12345')
    >>> m
    <_sre.SRE_Match object; span=(0, 9), match='010-12345'>
    >>> m.group(0)
    '010-12345'
    >>> m.group(1)
    '010'
    >>> m.group(2)
    '12345'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    如果正则表达式中定义了组,就可以在Match对象上用group()方法提取出子串来。

    注意到group(0)永远是与整个正则表达式相匹配的字符串,group(1)group(2)……表示第1、2、……个子串。

    贪婪匹配

    最后需要特别指出的是,正则匹配默认是贪婪匹配,也就是匹配尽可能多的字符。举例如下,匹配出数字后面的0

    >>> re.match(r'^(\d+)(0*)$', '102300').groups()
    ('102300', '')
    
    • 1
    • 2

    由于\d+采用贪婪匹配,直接把后面的0全部匹配了,结果0*只能匹配空字符串了。

    必须让\d+采用非贪婪匹配(也就是尽可能少匹配),才能把后面的0匹配出来,加个?就可以让\d+采用非贪婪匹配:

    >>> re.match(r'^(\d+?)(0*)$', '102300').groups()
    ('1023', '00')
    
    • 1
    • 2

    编译

    当我们在Python中使用正则表达式时,re模块内部会干两件事情:

    1. 编译正则表达式,如果正则表达式的字符串本身不合法,会报错;
    2. 用编译后的正则表达式去匹配字符串。

    如果一个正则表达式要重复使用几千次,出于效率的考虑,我们可以预编译该正则表达式,接下来重复使用时就不需要编译这个步骤了,直接匹配:

    >>> import re
    # 编译:
    >>> re_telephone = re.compile(r'^(\d{3})-(\d{3,8})$')
    # 使用:
    >>> re_telephone.match('010-12345').groups()
    ('010', '12345')
    >>> re_telephone.match('010-8086').groups()
    ('010', '8086')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    编译后生成Regular Expression对象,由于该对象自己包含了正则表达式,所以调用对应的方法时不用给出正则字符串。

  • 相关阅读:
    【JavaWeb】Day47.Mybatis基础操作——删除
    u-boot命令2
    map和set
    ansible服务搭建与windows引用
    Linker Script链接脚本说明
    【Unity面试】 Lua语言基础核心 | 面试真题 | 全面总结 | 建议收藏
    一文带你读懂云原生、微服务与高可用
    SpringCloud基于RocketMQ实现分布式事务
    web前端开发面试集合分享
    基于java+springmvc+mybatis+vue+mysql的班级管理系统
  • 原文地址:https://blog.csdn.net/Supreme7/article/details/132836954