Python基础学习之匹配与正则表达式

Python基础学习之匹配与正则表达式


前言

        正则表达式很有用,但如果不是程序员,很少会有人了解它,尽管大多数现代文本编辑器和文字处理器(诸如微软的 Word 或 OpenOffice),都有查找和查找替换功能,可以根据正则表达式查找。正则表达式可以节约大量时间,不仅适用于软件用户,也适用于程序员。本文章主要讲python的字符匹配与正则表达式


一、不用正则表达式查找

在python学习中经常会遇到字符串匹配提取问题,比如:

        Q1:告诉你某国手机号组成为:xxxx-xxx-xxx-xxxx(其中x为数字,如1234-123-123-1234),需要你输入一个字符串判断是不是电话。

        你会怎么解决呢?如果是我,我会先判断字符串的长度,如果长度都不一致,那肯定不是号码;然后判断每个’-’的位置对没;最后判断每段子字符串是纯数字。代码示例如下:

def checkIsPhone(num):
    if len(num) != 17:
        return False
    for i in range(0, 4):
        if not num[i].isdecimal():
            return False
    for i in range(5, 8):
        if not num[i].isdecimal():
            return False
    for i in range(9, 12):
        if not num[i].isdecimal():
            return False
    for i in range(13, 17):
        if not num[i].isdecimal():
            return False
    if num[4] != '-' or num[8] != '-' or num[12] != '-':
        return False
    return True
if __name__ == '__main__':
    phone = '1234-123-123-1234'
    phone1 = '1235-abc-123-1234'
    print(checkIsPhone(phone))
    #>>>True
    print(checkIsPhone(phone1))
    #>>>False

        因为号码只有17个,所以代码看起来还不算复杂。但是如果号码有很多个,里面的分段循环查找和符号’-’的查找是不是会有很多部分,代码就会很多且单一,让其他人阅读起来费劲。

        Q2:有一字符串里面可能包含电话号码,你需要从里面提取出来所有可能是电话号码的子字符串。在刚刚代码基础上添加如下代码:


def getPhone(str0):
    list = []
    if len(str0) < 17:
        return False
    else:
        for i in range(0, len(str0) - 17):
            str1 = str0[i:i + 17]
            if checkIsPhone(str1):
                list.append(str1)
        return list

示例字符串长度并不大,所以很快就有了结果,如果字符串长度十分庞大,运行时长也会增长。

二、用正则表达式进行匹配查找

就刚刚的问题,用正则表达式\d{4}-\d{3}-\d{3}-\d{3}处理,代码示例如下:

import re


string = '这是我的电话号码:1234-123-123-1234,4321-321-321-4321是我的银行卡号'
# 创建一个正则表达式对象
Reg = re.compile(r'\d{4}-\d{3}-\d{3}-\d{4}')
# 查找字符串所有符合的子字符串,返回子字符串列表
match = Reg.findall(string)
print(match)
# >>>['1234-123-123-1234', '4321-321-321-4321']
# 查找第一个符合的子字符串,返回一个Match对象  Match 对象有一个 group()方法,它返回被查找字
# 符串中实际匹配的文本
match1 = Reg.search(string).group()
print(match1)
# >>>1234-123-123-1234

        可以很明显的看出,使用正则表达式进行匹配查找,能高速有效的得出结果,且使你的代码简短明了。

三、正则表达式的更多匹配方式

1.利用括号分组

        假如你需要从一个句子里面提取身份证号里面的生日,添加括号在正则表达式里创建分组,用group()提取我们需要的生日号码。代码示例如下:

import re

# 其中20000125 是生日号码
str0 = '这是我的身份证号码:510211-20000125-3910'
Reg = re.compile(r'(\d{6})-(\d{8})-(\d{4})')
match = Reg.search(str0)
print(match.group(0))
# >>>510211-20000125-3910
print(match.group(1))
# >>>510211
print(match.group(2))
# >>>20000125
print(match.group(3))
# >>>3910

        向 group() 匹配对象方法传入整数 1 或2或3,就可以取得匹配文本的不同部分。向 group()方法传入 0 或不传入参数,将返回整个匹配的文本

2.用管道匹配多个分组

        字符|称为“管道”。希望匹配许多表达式中的一个时,就可以使用它。例如正则表达式r’Tom|Jerry’,将匹配’Tom’或者’Jerry’。代码示例如下:

import re

str1 = '波妞喜欢宗介,中介喜欢赚差价'
Reg1 = re.compile(r'波妞|宗介')
match = Reg1.findall(str1)
print(match)
# >>>['波妞', '宗介']
batRegex = re.compile(r'Bat(man|mobile|copter|bat)')
mo = batRegex.search('Batmobile lost a wheel')
print(mo.group())
# >>>Batmobile
print(mo.group(1))
# >>>mobile

        如果要匹配’|’,则需要转义字符’\|’。

3.用问号实现可选匹配

代码示例如下:


Reg = re.compile(r'super(wo)?man')
mo1 = Reg.search('The china of superman')
print(mo1.group())
# >>>superman
mo2 = Reg.search('The china of superwoman')
print(mo2.group())
# >>>superwoman

        正则表达式中的(wo)?部分表明,模式 wo 是可选的分组。该正则表达式匹配的文本中,wo 将出现零次或一次。

        如果需要匹配真正的问号字符,就使用转义字符\?。

4.用星号匹配零次或多次

        *(星号)意味着“匹配零次或多次”,即星号之前的分组,可以在文本中出现任意次。它可以完全不存在,或一次又一次地重复。代码示例如下:

batRegex = re.compile(r'super(wo)*man')
mo1 = batRegex.search('The china of superman')
print(mo1.group())
# >>>superman

mo2 = batRegex.search('The china of superwoman')
print(mo2.group())
# >>>superwoman

mo3 = batRegex.search('The china of superwowowowoman')
print(mo3.group())
# >>>superwowowowoman

        如果需要匹配真正的星号字符,就在正则表达式的星号字符前加上倒斜杠,即\*。

5.用加号匹配一次或多次

        *意味着“匹配零次或多次”,+(加号)则意味着“匹配一次或多次”。星号不要求分组出现在匹配的字符串中,但加号不同,加号前面的分组必须“至少出现一次”。这不是可选的。代码示例如下:

batRegex = re.compile(r'super(wo)+man')
mo1 = batRegex.search('The china of superman')
print(mo1)
# >>>None

mo2 = batRegex.search('The china of superwoman')
print(mo2.group())
# >>>superwoman

mo3 = batRegex.search('The china of superwowowowoman')
print(mo3.group())
# >>>superwowowowoman

6.用花括号匹配特定次数贪心和非贪心匹配

        如果想要一个分组重复特定次数,就在正则表达式中该分组的后面,跟上花括号包围的数字。例如,正则表达式(Ha){3}将匹配字符串'HaHaHa',但不会匹配'HaHa',因为后者只重复了(Ha)分组两次。

        除了一个数字,还可以指定一个范围,即在花括号中写下一个最小值、一个逗号和一个最大值。例如,正则表达式(Ha){3,5}将匹配'HaHaHa'、'HaHaHaHa'和'HaHaHaHaHa'。也可以不写花括号中的第一个或第二个数字,不限定最小值或最大值。例如,(Ha){3,}将匹配 3 次或更多次实例,(Ha){,5}将匹配 0 到 5 次实例。花括号让正则表达式更简短。

        Python 的正则表达式默认是“贪心”的,这表示在有二义的情况下,它们会尽可能匹配最长的字符串。花括号的“非贪心”版本匹配尽可能最短的字符串,即在结束的花括号后跟着一个问号。在交互式环境中输入以下代码,注意在查找相同字符串时,花括号的贪心形式 和非贪心形式之间的区别:

Regex = re.compile(r'(Ha){3,5}')
mo1 = Regex.search('HaHaHaHaHa')
print(mo1.group())
# >>>HaHaHaHaHa
Regex = re.compile(r'(Ha){3,5}?')
mo2 = Regex.search('HaHaHaHaHa')
print(mo2.group())
# >>>HaHaHa

7.findall()方法

        回一个Match 对象,包含被查找字符串中的“第一次”匹配的文本,而 findall()方法将返回一组字符串,包含被查找字符串中的所有匹配。findall()不是返回一个 Match 对象,而是返回一个字符串列表,只要 在正则表达式中没有分组。列表中的每个字符串都是一段被查找的文本,它匹配该正则表达式。代码示例如下:

reg = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')  # has no groups
mo = reg.findall('Cell: 415-555-9999 Work: 212-555-0000')
print(mo)
# >>>['415-555-9999', '212-555-0000']

        如果在正则表达式中有分组,那么 findall 将返回元组的列表。每个元组表示一个找到的匹配,其中的项就是正则表达式中每个分组的匹配字符串。代码示例如下:

reg = re.compile(r'(\d\d\d)-(\d\d\d)-(\d\d\d\d)')  # has groups
mo = reg.findall('Cell: 415-555-9999 Work: 212-555-0000')
print(mo)
# >>>[('415', '555', '1122'), ('212', '555', '0000')]

作为 findall()方法的返回结果的总结,请记住下面两点:

        1.如果调用在一个没有分组的正则表达式上,例如\d\d\d-\d\d\d-\d\d\d\d,方法findall()将返回一个匹配字符串的列表,例如['415-555-9999', '212-555-0000']。

        2.如果调用在一个有分组的正则表达式上,例如(\d\d\d)-(\d\d\d)-(\d\d\d\d),方法 findall()将返回一个字符串的元组的列表(每个分组对应一个字符串),例如[('415', '555', '1122'), ('212', '555', '0000')]。        

8.常用字符分类的缩写代码

缩写字符分类

表示

\w

任何字母、数字或下划线字符(可以认为是匹配“单词”字符)

\W

除字母、数字和下划线以外的任何字符

\s

空格、制表符或换行符(可以认为是匹配“空白”字符)

\S

除空格、制表符和换行符以外的任何字符

\d

0 到 9 的任何数字

\D

除 0 到 9 的数字以外的任何字符

9.用点-星匹配所有字符

        有时候想要匹配所有字符串。例如,假定想要匹配字符串'First Name:',接下来是任意文本,接下来是'Last Name:',然后又是任意文本。可以用点-星(.*)表示“任意文本”。示例代码如下:

# 9.用点-星匹配所有字符
nameRegex = re.compile(r'First Name: (.*) Last Name: (.*)')
mo = nameRegex.search('First Name: 波妞 Last Name: 宗介')
print(mo.group(1))
# >>>波妞
print(mo.group(2))
# >>>宗介

        点-星使用“贪心”模式:它总是匹配尽可能多的文本。要用“非贪心”模式匹配所有文本,就使用点-星和问号。像和大括号一起使用时那样,问号告诉 Python 用非贪心模式匹配。

10.用句点字符匹配换行

        点-星将匹配除换行外的所有字符。通过传入 re.DOTALL 作为 re.compile()的第二个参数,可以让句点字符匹配所有字符,包括换行字符。 示例代码如下:

# 10.用句点字符匹配换行
noNewlineRegex = re.compile('.*')
n = noNewlineRegex.search('Serve the public trust.\nProtect the innocent.\nUphold the law.').group()
print(n)
# >>>'Serve the public trust.'
newlineRegex = re.compile('.*', re.DOTALL)
m = newlineRegex.search('Serve the public trust.\nProtect the innocent.\nUphold the law.').group()
print(m)
# >>>'Serve the public trust.\nProtect the innocent.\nUphold the law.'

都看到这里了,如果觉得有用就留下你宝贵的赞吧!!!

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LLGululu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值