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

正则表达式

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

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

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

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

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

  • 基础

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

    例子:

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

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

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

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

    • 进阶

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

      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
      

字符转义的理解

在任意编程语言中,定义的一个用户的一个字符串,在被加载的时候不是不变的,比如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'
      
    • 方法2:re.escape

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

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

    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)
    

re.match函数

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

例子

import re

pattern = r".a."
url = "Aa9"

if re.match(pattern, url):
    print("匹配成功!") 
else:
    print("匹配失败!")
# 输出: 匹配成功

匹配邮箱

# 匹配邮箱
pattern = r'^[a-zA-Z0-9\.]+@[a-zA-Z0-9\.]+\.com$'
pattern = r'^[\w\.]+@[\w\.]+\.com$' # 简写

print(re.match(pattern,'[email protected]'))
print(re.match(pattern,'[email protected]'))
  • 扩展

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

    [email protected] => Tom Paris

    [email protected] => 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(' [email protected]') == 'Tom Paris'
    assert name_of_email('[email protected]') == 'tom'print('ok')
    

re.escape函数

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

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

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

语法如下

re.escape(string)

其中,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("匹配失败!")

切分字符串

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

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

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

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

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

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

再加入;试试:

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

分组

除了简单地判断是否匹配之外,正则表达式还有提取子串的强大功能。用()表示的就是要提取的分组(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'

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

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

贪婪匹配

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

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

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

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

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

编译

当我们在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')

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

你可能感兴趣的:(python,正则表达式,python)