正则匹配即查找并返回一个匹配项。

基本函数

re模块完成正则匹配功能的函数有3个:

  1. search: 从字符串任意位置开始匹配,返回第一个匹配成功的对象,匹配失败函数返回None
  2. match: 从字符串开头开始匹配,匹配失败函数返回None
  3. fullmatch: 整个字符串与正则完全匹配

    它们的参数均为:

    1. re.xxx(pattern, string, flags=0)

    search方法从字符串任意位置开始查找,适配性最强,可以通过加入 ^ 匹配开头达到跟match相同的 效果,match也可以通过加入 $ 匹配结尾达到跟fullmatch相同的效果。 首先测试一下search:

    1. print(re.search('www', 'www.taobao.com'))
    2. print(re.search('com', 'www.taobao.com'))
    1. <re.Match object; span=(0, 3), match='www'>
    2. <re.Match object; span=(11, 14), match='com'>

    测试match:

    1. print(re.match('www', 'www.taobao.com'))
    2. print(re.match('com', 'www.taobao.com'))
    1. <re.Match object; span=(0, 3), match='www'>
    2. None

    最后测试fullmatch:

    1. print(re.fullmatch('www', 'www.taobao.com'))
    2. print(re.fullmatch('com', 'www.taobao.com'))
    3. print(re.fullmatch('www.taobao.com', 'www.taobao.com'))
    1. None
    2. None
    3. <re.Match object; span=(0, 14), match='www.taobao.com'>

    从上述结果中,我们可以清晰的看到search、match和fullmatch三者的区别: 由于’com’在字符串’www.taobao.com’的末尾,所以match函数未匹配到任何结果返回None;而 fullmatch函数由于是匹配整个字符串,所以’www’匹配’www.taobao.com’时也返回None。

    re.MatchObject 对象

    同时可以看到,它们均返回了一个 re.Match 对象,该对象提供了group(num) 和 groups()方法, group(num) 用于返回对应分组编号的数据,groups()方法用于返回所有分组的数据,而lastindex属性 可以获取分组的个数。
    示例:

    1. line = "Cats are smarter than dogs"
    2. matchObj = re.match(r'(.*?) are (.*?) ', line, re.I)
    3. if matchObj:
    4. print("总分组数:", matchObj.lastindex)
    5. print("所有分组的数据:",matchObj.groups())
    6. print("整个被匹配的字符串 : ", matchObj.group())
    7. print("第1个分组的数据 : ", matchObj.group(1))
    8. print("第2个分组的数据 : ", matchObj.group(2))
    9. else:
    10. print("No match!!")

    结果:

    1. 总分组数: 2
    2. 所有分组的数据: ('Cats', 'smarter')
    3. 整个被匹配的字符串 : Cats are smarter
    4. 1个分组的数据 : Cats
    5. 2个分组的数据 : smarter

    re.MatchObject 对象的其他方法:

  • start() 返回匹配开始的位置 -
  • end() 返回匹配结束的位置
  • span() 返回一个元组包含匹配 (开始,结束) 的位置

    匹配手机号码

    目前主要的手机号前三位是:
    1. 中国电信号段:133153 180181189173 177149
    2. 中国联通号段:130131132155156185186145176185
    3. 中国移动号段:134135136137138139150151152157158159182
    4. 183184147178
    规律是:
    1. 第一位 1
    2. 第二位:34578
    3. 第三位:根据第二位来确定
    4. 3 + 0-9
    5. 4 + 579
    6. 5 + 0-9】!4
    7. 7 + 0-9】! 49
    8. 8 + 0-9
    对手机号比较粗略的匹配(11位数字,前2位符合手机号规则):
    1. "1[34578]\d{9}"
    较为精确的匹配(11位数字,前3位符合手机号规则):
    1. "1(?:[38]\d|4[579]|5[0-35-9]|7[0-35-8])\d{8}"
    测试较为精确匹配:
    ```python import re import random

def random_number(nums): result = “” for x in range(nums): result += str(random.randint(0, 9)) return result nums = [ 133, 153, 180, 181, 189, 173, 177, 149, 130, 131, 132, 155, 156, 185, 186, 145, 176, 185, 134, 135, 136, 137, 138, 139, 150, 151, 152, 157, 158, 159, 182, 183, 184, 147, 178 ] for num in nums: print(re.fullmatch(“1([38]\d|4[579]|5[0-35-9]|7[0-35-8])\d{8}”, f”{num}{random_number(8)}”).group(), end=”,”)

  1. 结果:
  2. ```python
  3. 13320640138,15352178619,18010467102,18124689139,18975065050,17380280568,17798
  4. 275371,14994833499,13068873816,13151192893,13289047370,15594125464,1564821694
  5. 0,18574982445,18643788553,14516397708,17616874062,18559031583,13443533383,135
  6. 96265766,13629806068,13745249866,13896644123,13954817486,15076523907,15182868
  7. 824,15229880699,15794102747,15852468936,15938064514,18297190705,18304331736,1
  8. 8402303981,14751356440,17847872471,

全部成功匹配上。 测试一个错误的电话号码:

  1. pattern = "1([38]\d|4[579]|5[0-35-9]|7[0-35-8])\d{8}"
  2. tel_number = "15452468936"
  3. print(re.fullmatch(pattern, tel_number))

结果:

  1. None

也成功的匹配失败。

匹配邮箱地址

邮箱地址的规则是: user@mail.server.name,即名称+@+网站 常见的邮箱地址一般都是@xxx.com,但也还包括一些特殊邮箱地址,能到三级域名甚至四级域名,例 如:

  1. @SEED.NET.TW @TOPMARKEPLG.COM.TW @wilnetonline.net @cal3.vsnl.net.in

当然这只是少部分,大部分都是二级域名,但我们不能因此让这些域名匹配不成功。 例如,我们认为下面的邮箱地址都是合法的邮箱地址:

  1. emails = [
  2. 'someone@gmail.com',
  3. 'bill.gates@microsoft.com',
  4. 'mr-bob@example.com',
  5. 'someone@SEED.NET.TW',
  6. 'chuck.gt@cal3.vsnl.net.in'
  7. ]

正则匹配规则可以写为:

  1. r"[a-z.-]+@[[a-zA-Z0-9]+(\.[a-zA-Z]+){1,3}"

测试:

  1. for email in emails:
  2. match_obj = re.match(r"[a-z.-]+@[[a-zA-Z0-9]+(\.[a-zA-Z]+){1,3}", email,re.I)
  3. if match_obj:
  4. print(match_obj.group(0))

结果:

  1. someone@gmail.com
  2. bill.gates@microsoft.com
  3. mr-bob@example.com
  4. someone@SEED.NET.TW
  5. chuck.gt@cal3.vsnl.net.in

再顺便测试一个不是邮箱的字符串:

  1. print(re.match(r"[a-z.-]+@[[a-zA-Z0-9]+(\.[a-zA-Z]+){1,3}",
  2. 'bob#example.com', re.I))

未通过校验,打印结果为None。

匹配时引用分组

前面的正则匹配规则表中说过:
\ 表示引用编号为 \ 的分组匹配到的字符串
示例
IT后台有一批用户名和密码的字符串,部门希望找出那些将密码设置的跟用户名一样的用户提醒他们修 改密码:

  1. users = [
  2. "user1:password",
  3. "user2:user2",
  4. "user3:password",
  5. "user4:password",
  6. "user5:password",
  7. "user6:user6",
  8. "user7:password",
  9. "user8:user8",
  10. "user9:password",
  11. "user10:user10"
  12. ]

这时,在匹配时引用分组就会非常方便:

  1. for user in users:
  2. match_obj = re.match(r"(\w+):\1", user, re.A)
  3. if match_obj:
  4. print(match_obj.group(1))

结果:

  1. user2
  2. user6
  3. user8
  4. user10

可以看到顺利的提取出了,用户名和密码一致的用户。