我心中的王者:Python-第16章 正则表达式(Regular Expression)

python使用正则表达式(Regular Expression)方法超详细 一、导入re库 python使用正则表达式要导入re库。 import re 在re库中。正则表达式通常被用来检索查找、替换那些符合某个模式(规则)的文本。 二、使用正则表达式步骤 1、寻找规律; 2、使用正则符号表示规律; 3、提取信息,如果每一个字符都能匹配,则匹配成功;一旦有匹配不成功的字符则匹配失败。 三、正则表达式中常见的基本符号 1.点号“.”     一个点号可以代替除了换行符(\n)以外的任何一个字符,包括但不限于英文字母、数字、汉字、英文标点符号和中文标点符号。 2.星号“*”     一个星号可以表示它前面的一个子表达式(普通字符、另一个或几个正则表达式符号)0次到无限 立即下载

我心中的王者:Python-第16章 正则表达式(Regular Expression)

正则表达式(Regular Expression)主要功能是执行模式的比对与搜寻,甚至Word文件也可以使用正则表达式处理搜寻(search)与取代(replace)功能,本章首先会介绍如果没用正则表达式,如何处理搜寻文字功能,再介绍使用正则表达式处理这类问题,读者会发现整个工作变得更简洁容易。

16-1 使用Python硬功夫搜寻文字

如果现在打开手机的联络信息可以看到,台湾手机号码的格式如下:

 0952-282-020  # 可以表示为xxxx-xxx-xxx,每个x代表一个0-9数字

从上述可以发现手机号码格式是由4个数字,1个连字符号,3个数字,1个连字符号,3个数字所组成。

程序实例ch16_1.py:用传统知识设计一个程序,然后判断字符串是否含有台湾的手机号码格式。

# ch16_1.py
def taiwanPhoneNum(string):
    """检查是否有含手机联络信息的台湾手机号码格式"""
    if len(string) != 12:       # 如果长度不是12
        return False            # 传回非手机号码格式
    
    for i in range(0, 4):       # 如果前4个字出现非数字字符
        if string[i].isdecimal() == False:
            return False        # 传回非手机号码格式
        
    if string[4] != '-':        # 如果不是'-'字符
        return False            # 传回非手机号码格式
   
    for i in range(5, 8):       # 如果中间3个字出现非数字字符
        if string[i].isdecimal() == False:
            return False        # 传回非手机号码格

    if string[8] != '-':        # 如果不是'-'字符
        return False            # 传回非手机号码格式

    for i in range(9, 12):      # 如果最后3个字出现非数字字符
        if string[i].isdecimal() == False:
            return False        # 传回非手机号码格
    return True                 # 通过以上测试

print("I love Ming-Chi: 是台湾手机号码", taiwanPhoneNum('I love Ming-Chi'))
print("0932-999-199:    是台湾手机号码", taiwanPhoneNum('0932-999-199'))

执行结果

I love Ming-Chi: 是台湾手机号码 False
0932-999-199:    是台湾手机号码 True

上述程序第4和5行是判断字符串长度是否12,如果不是则表示这不是手机号码格式。程序第7至9行是判断字符串前4码是不是数字,如果不是则表示这不是手机号码格式。程序第11至12行是判断这个字符是不是‘-’,如果不是则表示这不是手机号码格式。程序第14至16行是判断字符串索引[5][6][7]码是不是数字,如果不是则表示这不是手机号码格式。程序第18至19行是判断这个字符是不是‘-’,如果不是则表示这不是手机号码格式。程序第21至23行是判断字符串索引[9][10][11]码是不是数字,如果不是则表示这不是手机号码格式。如果通过了以上所有测试,表示这是手机号码格式,程序第24行传回True。

在真实的环境应用中,我们可能需面临一段文字,这段文字内穿插一些数字,然后我们必须将手机号码从这段文字抽离出来。

程序实例ch16_2.py:将电话号码从一段文字抽离出来。

# ch16_2.py
def taiwanPhoneNum(string):
    """检查是否有含手机联络信息的台湾手机号码格式"""
    if len(string) != 12:       # 如果长度不是12
        return False            # 传回非手机号码格式
    
    for i in range(0, 4):       # 如果前4个字出现非数字字符
        if string[i].isdecimal() == False:
            return False        # 传回非手机号码格式
        
    if string[4] != '-':        # 如果不是'-'字符
        return False            # 传回非手机号码格式
   
    for i in range(5, 8):       # 如果中间3个字出现非数字字符
        if string[i].isdecimal() == False:
            return False        # 传回非手机号码格

    if string[8] != '-':        # 如果不是'-'字符
        return False            # 传回非手机号码格式

    for i in range(9, 12):      # 如果最后3个字出现非数字字符
        if string[i].isdecimal() == False:
            return False        # 传回非手机号码格
    return True                 # 通过以上测试

def parseString(string):
    """解析字符串是否含有电话号码"""
    notFoundSignal = True       # 注记没有找到电话号码为True
    for i in range(len(string)):  # 用循环逐步抽取12个字符做测试
        msg = string[i:i+12]
        if taiwanPhoneNum(msg):
            print("电话号码是: %s" % msg)
            notFoundSignal = False        
    if notFoundSignal:          # 如果没有找到电话号码则打印
        print("%s 字符串不含电话号码" % string)

msg1 = 'Please call my secretary using 0930-919-919 or 0952-001-001'
msg2 = '请明天17:30和我一起参加明志科大教师节晚餐'
msg3 = '请明天17:30和我一起参加明志科大教师节晚餐, 可用0933-080-080联络我'
parseString(msg1)
parseString(msg2)
parseString(msg3)

执行结果

电话号码是: 0930-919-919
电话号码是: 0952-001-001
请明天17:30和我一起参加明志科大教师节晚餐 字符串不含电话号码
电话号码是: 0933-080-080

从上述执行结果可以得知我们成功地从一个字符串分析,然后将电话号码分析出来了。分析方式的重点是程序第26行到35行的parseString函数,这个函数重点是第29至33行,这个循环会逐步抽取字符串的12个字符做比对,将比对字符串放在msg字符串变量内,下列是各循环次序的msg字符串变量内容。
在这里插入图片描述

程序第28行将没有找到电话号码notFoundSignal设为True,如果有找到电话号码程序33行将notFoundSignal标示为False,当parseString( )函数执行完,notFoundSignal仍是True,表示没找到电话号码,所以第35行打印字符串不含电话号码。

上述使用所学的Python硬功夫虽然解决了我们的问题,但是若是将电话号码改成中国大陆手机号(xxx-xxxx-xxxx)、美国手机号(xxx-xxx-xxxx)或是一般公司行号的电话,整个号码格式不一样,要重新设计可能需要一些时间。不过不用担心,接下来笔者将讲解的Python的正则表达式可以轻松解决上述困扰。

16-2 正则表达式的基础

Python有关正则表达式的方法是在re模块内,所以使用正则表达式需要导入re模块。

import re # 导入re模块

16-2-1 建立搜寻字符串模式

在前一节我们使用isdecimal( )方法判断字符是否是0—9的数字。

正则表达式是一种文本模式的表达方法,在这个方法中使用\d表示0—9的数字字符,采用这个观念我们可以将前一节的手机号码xxxx-xxx-xxx改用下列正则表达方式表示:

 '\d\d\d\d-\d\d\d-\d\d\d'

由逸出字符的观念可知,将上述表达式当字符串放入函数内需增加‘\’,所以整个正则表达式的使用方式如下:

 '\\d\\d\\d\\d-\\d\\d\\d-\\d\\d\\d'

在3-4-9小节笔者有介绍字符串前加r可以防止字符串内的逸出字符被转译,所以又可以将上述正则表达式简化为下列格式:

 r'\d\d\d\d-\d\d\d-\d\d\d'

16-2-2 使用re.compile( )建立Regex对象

Regex是Regular expression的简称,在re模块内有compile( )方法,可以将16-2-1节的欲搜寻字符串的正则表达式当作字符串参数放在此方法内,然后会传回一个Regex对象。如下所示:

   phoneRule = re.compile(r'\d\d\d\d-\d\d\d-\d\d\d') # 建立phoneRule对象

16-2-3 搜寻对象

在Regex对象内有search( )方法,可以由Regex对象启用,然后将欲搜寻的字符串放在这个方法内,沿用上述观念程序片段如下:

 phoneNum = phoneRule.search(msg)  # msg是欲搜寻的字符串

如果找不到比对相符的字符串会传回None,如果找到比对相符的字符串会将结果传回所设定的phoneNum变量对象,这个对象在Python中称之为MatchObject对象,将在16-6节完整解说。现在笔者将介绍实用性较高的部分,处理此对象主要是将搜寻结果传回,我们可以用group( )方法将结果传回,不过search( )将只传回第一个比对相符的字符串。

程序实例ch16_3.py:使用正则表达式重新设计ch16_2.py。

# ch16_3.py
import re

msg1 = 'Please call my secretary using 0930-919-919 or 0952-001-001'
msg2 = '请明天17:30和我一起参加明志科大教师节晚餐'
msg3 = '请明天17:30和我一起参加明志科大教师节晚餐, 可用0933-080-080联络我'

def parseString(string):
    """解析字符串是否含有电话号码"""
    phoneRule = re.compile(r'\d\d\d\d-\d\d\d-\d\d\d')
    phoneNum = phoneRule.search(string)
    if phoneNum != None:        # 检查phoneNum内容
        print("电话号码是: %s" % phoneNum.group())
    else:
        print("%s 字符串不含电话号码" % string)

parseString(msg1)
parseString(msg2)
parseString(msg3)

执行结果

电话号码是: 0930-919-919
请明天17:30和我一起参加明志科大教师节晚餐 字符串不含电话号码
电话号码是: 0933-080-080

在程序实例ch16_2.py我们使用了约21行做字符串解析,当我们使用Python的正则表达式时,只用第10和11行共2行就解析了字符串是否含手机号码了,整个程序变得简单许多。不过上述msg1字符串内含2组手机号码,使用search( )只传回第一个发现的号码,下一节将改良此方法。

16-2-4 findall( )

从方法的名字就可以知道,这个方法可以传回所有找到的手机号码。这个方法会将搜寻到的手机号码用列表方式传回,这样就不会有只显示第一个搜寻到的手机号码的缺点,如果没有比对相符的号码就传回[ ]空列表。要使用这个方法的关键指令如下:

  phoneRule = re.compile(r'\d\d\d\d-\d\d\d-\d\d\d') # 建立phoneRule对象
  phoneNum = phoneRule.findall(string)                 # string是欲搜寻的字符串

findall( )函数由phoneRule对象启用,最后会将搜寻结果的列表传给phoneNum,只要打印phoneNum就可以得到执行结果。

程序实例ch16_4.py:使用findall( )搜寻字符串,第10行定义正则表达式,打印结果。

# ch16_4.py
import re

msg1 = 'Please call my secretary using 0930-919-919 or 0952-001-001'
msg2 = '请明天17:30和我一起参加明志科大教师节晚餐'
msg3 = '请明天17:30和我一起参加明志科大教师节晚餐, 可用0933-080-080联络我'

def parseString(string):
    """解析字符串是否含有电话号码"""
    phoneRule = re.compile(r'\d\d\d\d-\d\d\d-\d\d\d')
    phoneNum = phoneRule.findall(string)     # 用列表传回搜寻结果
    print("电话号码是: %s" % phoneNum)       # 列表方式显示电话号码

parseString(msg1)
parseString(msg2)
parseString(msg3)

执行结果

电话号码是: ['0930-919-919', '0952-001-001']
电话号码是: []
电话号码是: ['0933-080-080']

16-2-5 再看re模块

其实Python语言的re模块对于search( )和findall( )有提供更强的功能,可以省略使用re.compile( )直接将比对模式放在各自的参数内,此时语法格式如下:

   re.search(pattern, string, flags)
   re.findall(pattern, string, flags)

上述pattern是欲搜寻的正则表达方式,string是所搜寻的字符串,flags可以省略,未来会介绍几个flags常用相关参数的应用。

程序实例ch16_5.py:使用re.search( )重新设计ch16_3.py,由于省略了re.compile( ),所以读者需留意第11行内容写法。

# ch16_5.py
import re

msg1 = 'Please call my secretary using 0930-919-919 or 0952-001-001'
msg2 = '请明天17:30和我一起参加明志科大教师节晚餐'
msg3 = '请明天17:30和我一起参加明志科大教师节晚餐, 可用0933-080-080联络我'

def parseString(string):
    """解析字符串是否含有电话号码"""
    pattern = r'\d\d\d\d-\d\d\d-\d\d\d'
    phoneNum = re.search(pattern, string)
    if phoneNum != None:        # 如果phoneNum不是None表示取得号码
        print("电话号码是: %s" % phoneNum.group())
    else:
        print("%s 字符串不含电话号码" % string)

parseString(msg1)
parseString(msg2)
parseString(msg3)

执行结果 与ch16_3.py相同。

程序实例ch16_6.py:使用re.findall( )重新设计ch16_4.py,由于省略了re.compile( ),所以读者需留意第11行内容写法。

# ch16_6.py
import re

msg1 = 'Please call my secretary using 0930-919-919 or 0952-001-001'
msg2 = '请明天17:30和我一起参加明志科大教师节晚餐'
msg3 = '请明天17:30和我一起参加明志科大教师节晚餐, 可用0933-080-080联络我'

def parseString(string):
    """解析字符串是否含有电话号码"""
    pattern = r'\d\d\d\d-\d\d\d-\d\d\d'
    phoneNum = re.findall(pattern, string)   # 用列表传回搜寻结果
    print("电话号码是: %s" % phoneNum)       # 列表方式显示电话号码

parseString(msg1)
parseString(msg2)
parseString(msg3)

执行结果 与ch16_4.py相同。

16-2-6 再看正则表达式

下列是我们目前的正则表达式所搜寻的字符串模式:

 r'\d\d\d\d-\d\d\d-\d\d\d'

其中可以看到\d重复出现,对于重复出现的字符串可以用大括号内部加上重复次数方式表达,所以上述可以用下列方式表达。

 r'\d{4}-\d{3}-\d{3}'

程序实例ch16_7.py:使用本节观念重新设计ch16_6.py,下列只列出不一样的程序内容。
在这里插入图片描述

# ch16_7.py
import re

msg1 = 'Please call my secretary using 0930-919-919 or 0952-001-001'
msg2 = '请明天17:30和我一起参加明志科大教师节晚餐'
msg3 = '请明天17:30和我一起参加明志科大教师节晚餐, 可用0933-080-080联络我'

def parseString(string):
    """解析字符串是否含有电话号码"""
    pattern = r'\d{4}-\d{3}-\d{3}'
    phoneNum = re.findall(pattern, string)   # 用列表传回搜寻结果
    print("电话号码是: %s" % phoneNum)       # 列表方式显示电话号码

parseString(msg1)
parseString(msg2)
parseString(msg3)

执行结果 与ch16_4.py相同。

16-3 更多搜寻比对模式

先前我们所用的实例是手机号码,想想看如果我们改用市区电话号码的比对,台北市的电话号码如下:

 02-28350000  # 可用xx-xxxxxxxx表达

下列将以上述电话号码模式说明。

16-3-1 使用小括号分组

依照16-2节的观念,可以用下列正则表示法表达上述市区电话号码。

  r'\d\d-\d\d\d\d\d\d\d\d'

所谓括号分组是以连字符“-”区别,然后用小括号隔开群组,可以用下列方式重新规划上述表达式。也可简化为:

 r'(\d\d)-(\d\d\d\d\d\d\d\d')
 r'(\d{2})-(\d{8})'

当使用re.search( )执行比对时,未来可以使用group( )传回比对符合的不同分组,例如:group( )或group(0)传回第一个比对相符的文字与ch16_3.py观念相同。如果group(1)则传回括号的第一组文字,group(2)则传回括号的第二组文字。

程序实例ch16_8.py:使用小括号分组的观念,将分组内容输出。

# ch16_8.py
import re

msg = 'Please call my secretary using 02-26669999'
pattern = r'(\d{2})-(\d{8})'
phoneNum = re.search(pattern, msg)           # 传回搜寻结果

print("完整号码是: %s" % phoneNum.group())   # 显示完整号码
print("完整号码是: %s" % phoneNum.group(0))  # 显示完整号码
print("区域号码是: %s" % phoneNum.group(1))  # 显示区域号码
print("电话号码是: %s" % phoneNum.group(2))  # 显示电话号码

执行结果

完整号码是: 02-26669999
完整号码是: 02-26669999
区域号码是: 02
电话号码是: 26669999

如果所搜寻比对的正则表达式字符串有用小括号分组,若是使用findall( )方法处理,会传回元组(tuple)的列表(list),元组内的每个元素就是搜寻的分组内容。

程序实例ch16_9.py:使用findall( )重新设计ch16_8.py,这个实例会多增加一组电话号码。

# ch16_9.py
import re

msg = 'Please call my secretary using 02-26669999 or 02-11112222'
pattern = r'(\d{2})-(\d{8})'
phoneNum = re.findall(pattern, msg)           # 传回搜寻结果
print(phoneNum)

执行结果

[('02', '26669999'), ('02', '11112222')]

16-3-2 groups( )

注意这是groups( ),有在group后面加上s,当我们使用re.search( )搜寻字符串时,可以使用这个方法取得分组的内容。这时还可以使用2-9节的多重指定的观念,若以ch16_8.py为例,在第7行我们可以使用下列多重指定获得区域号码和当地电话号码。

  areaNum, localNum = phoneNum.groups( )  # 多重指定

程序实例ch16_10.py:重新设计ch16_8.py,分别列出区域号码与电话号码。

# ch16_10.py
import re

msg = 'Please call my secretary using 02-26669999'
pattern = r'(\d{2})-(\d{8})'
phoneNum = re.search(pattern, msg)      # 传回搜寻结果
areaNum, localNum = phoneNum.groups()   # 留意是groups()
print("区域号码是: %s" % areaNum)       # 显示区域号码
print("电话号码是: %s" % localNum)      # 显示电话号码

执行结果

区域号码是: 02
电话号码是: 26669999

16-3-3 区域号码是在小括号内

在一般电话号码的使用中,常看到区域号码是用小括号包夹,如下所示:

 (02)-26669999

在处理小括号时,方式是(和),可参考下列实例。

程序实例ch16_11.py:重新设计ch16_10.py,第4行的区域号码是(02),读者需留意第4行和第5行的设计。

# ch16_11.py
import re

msg = 'Please call my secretary using (02)-26669999'
pattern = r'(\(\d{2}\))-(\d{8})'
phoneNum = re.search(pattern, msg)      # 传回搜寻结果
areaNum, localNum = phoneNum.groups()   # 留意是groups()
print("区域号码是: %s" % areaNum)       # 显示区域号码
print("电话号码是: %s" % localNum)      # 显示电话号码

执行结果

区域号码是: (02)
电话号码是: 26669999

16-3-4 使用管道|

|(pipe)在正规表示法称管道,使用管道我们可以同时搜寻比对多个字符串,例如,想要搜寻Mary和Tom字符串,可以使用下列表示。

pattern = 'Mary|Tom'  # 注意单引号'或|旁不可留空白

程序实例ch16_12.py:管道搜寻多个字符串的实例。

# ch16_12.py
import re

msg = 'John and Tom will attend my party tonight. John is my best friend.'
pattern = 'John|Tom'                # 搜寻John和Tom
txt = re.findall(pattern, msg)      # 传回搜寻结果
print(txt)
pattern = 'Mary|Tom'                # 搜寻Mary和Tom
txt = re.findall(pattern, msg)      # 传回搜寻结果
print(txt)

执行结果

['John', 'Tom', 'John']
['Tom']

16-3-5 多个分组的管道搜寻

假设有一个字符串内容如下:

 Johnson, Johnnason and Johnnathan will attend my party tonight.

由上述可知,如果想要搜寻字符串比对John后面可以是son、nason、nathan任一个字符串的组合,可以使用下列正则表达式格式:

 pattern = John(son|nason|nathan)

程序实例ch16_13.py:搜寻Johnson、Johnnason或Johnnathan任一字符串,然后列出结果,这个程序将列出第一个搜寻比对到的字符串。

# ch16_13.py
import re

msg = 'Johnson, Johnnason and Johnnathan will attend my party tonight.'
pattern = 'John(son|nason|nathan)'
txt = re.search(pattern,msg)    # 传回搜寻结果
print(txt.group())              # 打印第一个搜寻结果
print(txt.group(1))             # 打印第一个分组

执行结果

Johnson
son

同样的正则表达式若是使用findall( )方法处理,将只传回各分组搜寻到的字符串,如果要列出完整的内容,可以用循环同时为每个分组字符串加上前导字符串John。

程序实例ch16_14.py:使用findall( )重新设计ch16_13.py。

# ch16_14.py
import re

msg = 'Johnson, Johnnason and Johnnathan will attend my party tonight.'
pattern = 'John(son|nason|nathan)'
txts = re.findall(pattern,msg)      # 传回搜寻结果
print(txts)
for txt in txts:                    # 将搜寻到内容加上John
    print('John'+txt)

执行结果

['son', 'nason', 'nathan']
Johnson
Johnnason
Johnnathan

16-3-6 使用?号做搜寻

在正则表达式中若某些括号内的字符串或正则表达式可有可无,执行搜寻时皆算成功,例如,na字符串可有可无,表达方式是(na)?。

程序实例ch16_15.py:使用?搜寻的实例,这个程序会测试2次。

# ch16_15.py
import re
# 测试1
msg = 'Johnson will attend my party tonight.'
pattern = 'John((na)?son)'
txt = re.search(pattern,msg)      # 传回搜寻结果
print(txt.group())
# 测试2
msg = 'Johnnason will attend my party tonight.'
pattern = 'John((na)?son)'
txt = re.search(pattern,msg)      # 传回搜寻结果
print(txt.group())

执行结果

Johnson
Johnnason

有时候如果居住在同一个城市,在留电话号码时,可能不会留区域号码,这时就可以使用本功能了。请参考下列实例第11行。

程序实例ch16_16.py:这个程序在搜寻电话号码时,即使省略区域号码程序也可以搜寻到此号码,然后打印出来,正则表达式格式请留意第6行。

# ch16_16.py
import re

# 测试1
msg = 'Please call my secretary using 02-26669999'
pattern = r'(\d\d-)?(\d{8})'                 # 增加?号
phoneNum = re.search(pattern, msg)           # 传回搜寻结果
print("完整号码是: %s" % phoneNum.group())   # 显示完整号码

# 测试2
msg = 'Please call my secretary using 26669999'
pattern = r'(\d\d-)?(\d{8})'                 # 增加?号
phoneNum = re.search(pattern, msg)           # 传回搜寻结果
print("完整号码是: %s" % phoneNum.group())   # 显示完整号码

执行结果

完整号码是: 02-26669999
完整号码是: 26669999

16-3-7 使用*号做搜寻

在正则表达式中若某些字符串或正则表达式可从0到多次,执行搜寻时皆算成功,例如,na字符串可从0到多次,表达方式是(na)*。

程序实例ch16_17.py:这个程序的重点是第5行的正则表达式,其中字符串na的出现次数可以是从0到多次。

# ch16_17.py
import re
# 测试1
msg = 'Johnson will attend my party tonight.'
pattern = 'John((na)*son)'        # 字符串na可以0到多次
txt = re.search(pattern,msg)      # 传回搜寻结果
print(txt.group())
# 测试2
msg = 'Johnnason will attend my party tonight.'
pattern = 'John((na)*son)'        # 字符串na可以0到多次
txt = re.search(pattern,msg)      # 传回搜寻结果
print(txt.group())
# 测试3
msg = 'Johnnananason will attend my party tonight.'
pattern = 'John((na)*son)'        # 字符串na可以0到多次
txt = re.search(pattern,msg)      # 传回搜寻结果
print(txt.group())

执行结果

Johnson
Johnnason
Johnnananason

16-3-8 使用+号做搜寻

在正则表达式中若是某些字符串或正则表达式可从1到多次,执行搜寻时皆算成功,例如,na字符串可从1到多次,表达方式是(na)+。

程序实例ch16_18.py:这个程序的重点是第5行的正则表达式,其中字符串na的出现次数可以是从1到多次。

# ch16_18.py
import re
# 测试1
msg = 'Johnson will attend my party tonight.'
pattern = 'John((na)+son)'        # 字符串na可以1到多次
txt = re.search(pattern,msg)      # 传回搜寻结果
print(txt)                        # 请注意是直接打印对象
# 测试2
msg = 'Johnnason will attend my party tonight.'
pattern = 'John((na)+son)'        # 字符串na可以1到多次
txt = re.search(pattern,msg)      # 传回搜寻结果
print(txt.group())
# 测试3
msg = 'Johnnananason will attend my party tonight.'
pattern = 'John((na)+son)'        # 字符串na可以1到多次
txt = re.search(pattern,msg)      # 传回搜寻结果
print(txt.group())

执行结果

None
Johnnason
Johnnananason

16-3-9 搜寻时忽略大小写

搜寻时若是在search( )或findall( )内增加第三个参数re.I或re.IGNORECASE,搜寻时就会忽略大小写,至于打印输出时将以原字符串的格式显示。

程序实例ch16_19.py:以忽略大小写方式执行找寻相符字符串。

# ch16_19.py
import re

msg = 'john and TOM will attend my party tonight. JOHN is my best friend.'
pattern = 'John|Tom'                        # 搜寻John和Tom
txt = re.findall(pattern, msg, re.I)        # 传回搜寻忽略大小写的结果
print(txt)
pattern = 'Mary|tom'                        # 搜寻Mary和tom
txt = re.findall(pattern, msg, re.I)        # 传回搜寻忽略大小写的结果
print(txt)

执行结果

['john', 'TOM', 'JOHN']
['TOM']

16-4 贪婪与非贪婪搜寻

16-4-1 搜寻时使用大括号设定比对次数

在16-2-6节我们有使用过大括号,当时讲解\d{4}代表重复4次,也就是大括号的数字是设定重复次数。可以将这个观念应用在搜寻一般字符串,例如,(son){3}代表所搜寻的字符串是‘sonsonson’,如果有一字符串是‘sonson’,则搜寻结果是不符。大括号除了可以设定重复次数,也可以设定指定范围,例如,(son){3,5}代表所搜寻的字符串如果是‘sonsonson’‘sonsonsonson’或‘sonsonsonsonson’皆算是相符合的字符串。(son){3,5}正则表达式相当于下列表达式:

((son)(son)(son))|((son)(son)(son)(son))|((son)(son)(son)(son)(son))

程序实例ch16_20.py:设定搜寻son字符串重复3-5次皆算搜寻成功。

# ch16_20.py
import re

def searchStr(pattern, msg):
    txt = re.search(pattern, msg)
    if txt == None:         # 搜寻失败
        print("搜寻失败 ",txt)
    else:                   # 搜寻成功
        print("搜寻成功 ",txt.group())

msg1 = 'son'
msg2 = 'sonson'
msg3 = 'sonsonson'
msg4 = 'sonsonsonson'
msg5 = 'sonsonsonsonson'
pattern = '(son){3,5}'
searchStr(pattern,msg1)
searchStr(pattern,msg2)
searchStr(pattern,msg3)
searchStr(pattern,msg4)
searchStr(pattern,msg5)

执行结果

搜寻失败  None
搜寻失败  None
搜寻成功  sonsonson
搜寻成功  sonsonsonson
搜寻成功  sonsonsonsonson

使用大括号时,也可以省略第一或第二个数字,这相当于不设定最小或最大重复次数。例如:(son){3,}代表重复3次以上皆符合,(son){,10}代表重复10次以下皆符合。有关这方面的实作,将留给读者练习,可参考习题3。

16-4-2 贪婪与非贪婪搜寻

在讲解贪婪与非贪婪搜寻前,笔者先简化程序实例ch16_20.py,使用相同的搜寻模式‘(son){3,5}’,搜寻字符串是‘sonsonsonsonson’,看看结果。

程序实例ch16_21.py:使用搜寻模式‘(son){3,5}’,搜寻字符串‘sonsonsonsonson’。

# ch16_21.py
import re

def searchStr(pattern, msg):
    txt = re.search(pattern, msg)
    if txt == None:         # 搜尋失敗
        print("搜尋失敗 ",txt)
    else:                   # 搜尋成功
        print("搜尋成功 ",txt.group())

msg = 'sonsonsonsonson'
pattern = '(son){3,5}'
searchStr(pattern,msg)

执行结果

搜尋成功  sonsonsonsonson

其实由上述程序所设定的搜寻模式可知3、4或5个son重复就算找到了,可是Python执行结果是列出最多重复的字符串,5次重复,这是Python的默认模式,这种模式又称贪婪(greedy)模式。

另一种是列出最少重复的字符串,以这个实例而言是重复3次,这称非贪婪模式,方法是在正则表达式的搜寻模式右边增加?符号。

程序实例ch16_22.py:以非贪婪模式重新设计ch16_21.py,请读者留意第12行的正则表达式的搜寻模式最右边的?符号。
在这里插入图片描述

# ch16_22.py
import re

def searchStr(pattern, msg):
    txt = re.search(pattern, msg)
    if txt == None:         # 搜寻失败
        print("搜寻失败 ",txt)
    else:                   # 搜寻成功
        print("搜寻成功 ",txt.group())

msg = 'sonsonsonsonson'
pattern = '(son){3,5}?'     # 非贪婪模式
searchStr(pattern,msg)

执行结果

搜寻成功  sonsonson

16-5 正则表达式的特殊字符

为了不让一开始学习正则表达式太复杂,在前面4个小节笔者只介绍了\d,同时穿插介绍一些字符串的搜寻。我们知道\d代表的是数字字符,也就是从0-9的阿拉伯数字,如果使用管道|的观念,\d相当于是下列正则表达式:

(0|1|2|3|4|5|6|7|8|9)

这一节将针对正则表达式的特殊字符做一个完整的说明。

16-5-1 特殊字符表

在这里插入图片描述

下列是一些使用上述表格观念的正则表达式的实例说明。

程序实例ch16_23.py:将一段英文句子的单词分离,同时将英文单词前4个字母是“John”的单词筛选出来。笔者设定如下:

 pattern = ‘\w+'      # 意义是把不限长度的数字、字母和底线字符当作符合搜寻
 pattern = ‘John\w*'  # John开头后面接0~多个数字、字母和底线字符
# ch16_23.py
import re
# 测试1将字符串从句子分离
msg = 'John, Johnson, Johnnason and Johnnathan will attend my party tonight.'
pattern = '\w+'                    # 不限长度的单字
txt = re.findall(pattern,msg)      # 传回搜寻结果
print(txt)
# 测试2将John开始的字符串分离
msg = 'John, Johnson, Johnnason and Johnnathan will attend my party tonight.'
pattern = 'John\w*'                # John开头的单字
txt = re.findall(pattern,msg)      # 传回搜寻结果
print(txt)

执行结果

['John', 'Johnson', 'Johnnason', 'and', 'Johnnathan', 'will', 'attend', 'my', 'party', 'tonight']
['John', 'Johnson', 'Johnnason', 'Johnnathan']

程序实例ch16_24.py:正则表达式的应用,下列程序重点是第5行。

\d+:表示不限长度的数字。

\s:表示空格。

\w+:表示不限长度的数字、字母和底线字符连续字符。

# ch16_24.py
import re

msg = '1 cat, 2 dogs, 3 pigs, 4 swans'
pattern = '\d+\s\w+'
txt = re.findall(pattern,msg)      # 传回搜寻结果
print(txt)

执行结果

['1 cat', '2 dogs', '3 pigs', '4 swans']

16-5-2 字符分类

Python可以使用中括号来设定字符,可参考下列范例。

[a-z]:代表a-z的小写字符。

[A-Z]:代表A-Z的大写字符。

[aeiouAEIOU]:代表英文发音的元音字符。

[2-5]:代表2-5的数字。

在字符分类中,中括号内可以不用放上正则表示法的反斜杠\执行.、?、*、(、)等字符的转译。例如,[2-5.]会搜寻2-5的数字和句点,这个语法不用写成[2-5.]。

程序实例ch16_25.py:搜寻字符的应用,这个程序首先将搜寻[aeiouAEIOU],然后将搜寻[2-5.]。

# ch16_25.py
import re
# 测试1搜寻[aeiouAEIOU]字符
msg = 'John, Johnson, Johnnason and Johnnathan will attend my party tonight.'
pattern = '[aeiouAEIOU]'           
txt = re.findall(pattern,msg)      # 传回搜寻结果
print(txt)
# 测试2搜寻[2-5.]字符
msg = '1. cat, 2. dogs, 3. pigs, 4. swans'
pattern = '[2-5.]'
txt = re.findall(pattern,msg)      # 传回搜寻结果
print(txt)

执行结果

['o', 'o', 'o', 'o', 'a', 'o', 'a', 'o', 'a', 'a', 'i', 'a', 'e', 'a', 'o', 'i']
['.', '2', '.', '3', '.', '4', '.']

16-5-3 字符分类的^字符

在16-5-2小节字符的处理中,如果在中括号内的左方加上^字符,意义是搜寻不在这些字符内的所有字符。

程序实例ch16_26.py:使用字符分类的^字符重新设计ch16_25.py。

# ch16_26.py
import re
# 测试1搜寻不在[aeiouAEIOU]的字符
msg = 'John, Johnson, Johnnason and Johnnathan will attend my party tonight.'
pattern = '[^aeiouAEIOU]'           
txt = re.findall(pattern,msg)      # 传回搜寻结果
print(txt)
# 测试2搜寻不在[2-5.]的字符
msg = '1. cat, 2. dogs, 3. pigs, 4. swans'
pattern = '[^2-5.]'
txt = re.findall(pattern,msg)      # 传回搜寻结果
print(txt)

执行结果

['J', 'h', 'n', ',', ' ', 'J', 'h', 'n', 's', 'n', ',', ' ', 'J', 'h', 'n', 'n', 's', 'n', ' ', 'n', 'd', ' ', 'J', 'h', 'n', 'n', 't', 'h', 'n', ' ', 'w', 'l', 'l', ' ', 't', 't', 'n', 'd', ' ', 'm', 'y', ' ', 'p', 'r', 't', 'y', ' ', 't', 'n', 'g', 'h', 't', '.']
['1', ' ', 'c', 'a', 't', ',', ' ', ' ', 'd', 'o', 'g', 's', ',', ' ', ' ', 'p', 'i', 'g', 's', ',', ' ', ' ', 's', 'w', 'a', 'n', 's']

上述第一个测试结果不会出现[aeiouAEIOU]字符,第二个测试结果不会出现[2-5.]字符。

16-5-4 正则表示法的^字符

这个字符与16-5-3小节的字符完全相同,但是用在不一样的地方,意义不同。在正规表示法中起始位置加上^字符,表示正则表示法的字符串必须出现在被搜寻字符串的起始位置,这样搜寻成功才算成功。

程序实例ch16_27.py:正则表示法^字符的应用,测试1字符串John是在最前面所以可以得到搜寻结果,测试2字符串John不是在最前面,结果搜寻失败传回空字符串。

# ch16_27.py
import re
# 测试1搜寻John字符串在最前面
msg = 'John will attend my party tonight.'
pattern = '^John'           
txt = re.findall(pattern,msg)      # 传回搜寻结果
print(txt)
# 测试2搜寻John字符串不是在最前面
msg = 'My best friend is John'
pattern = '^John'
txt = re.findall(pattern,msg)      # 传回搜寻结果
print(txt)

执行结果

['John']
[]

16-5-5 正则表示法的$字符

正则表示法的末端放置$字符时,表示正则表示法的字符串必须出现在被搜寻字符串的最后位置,这样搜寻成功才算成功。

程序实例ch16_28.py:正则表示法$字符的应用,测试1是搜寻字符串结尾是非英文字符、数字和底线字符,由于结尾字符是“.”,所以传回所搜寻到的字符。测试2是搜寻字符串结尾是非英文字符、数字和底线字符,由于结尾字符是“8”,所以传回搜寻结果是空字符串。测试3是搜寻字符串结尾是数字字符,由于结尾字符是“8”,所以传回搜寻结果“8”。测试4是搜寻字符串结尾是数字字符,由于结尾字符是“.”,所以传回搜寻结果空字符串。

# ch16_28.py
import re
# 测试1搜寻最后字符是非英文字母数字和底线字符
msg = 'John will attend my party 28 tonight.'
pattern = '\W$'           
txt = re.findall(pattern,msg)      # 传回搜寻结果
print(txt)
# 测试2搜寻最后字符是非英文字母数字和底线字符
msg = 'I am 28'
pattern = '\W$'
txt = re.findall(pattern,msg)      # 传回搜寻结果
print(txt)
# 测试3搜寻最后字符是数字
msg = 'I am 28'
pattern = '\d$'
txt = re.findall(pattern,msg)      # 传回搜寻结果
print(txt)
# 测试4搜寻最后字符是数字
msg = 'I am 28 year old.'
pattern = '\d$'
txt = re.findall(pattern,msg)      # 传回搜寻结果
print(txt)

执行结果

['.']
[]
['8']
[]

我们也可以将16-5-4小节的^字符和$字符混合使用,这时如果既要符合开始字符串也要符合结束字符串,所以被搜寻的句子一定要只有一个字符串。

程序实例ch16_29.py:搜寻开始到结束皆是数字的字符串,字符串内容只要有非数字字符就算搜寻失败。测试2中由于中间有非数字字符,所以搜寻失败。读者应留意程序第5行的正则表达式的写法。

# ch16_29.py
import re
# 测试1搜寻开始或结尾皆是数字的字符串
msg = '09282028222'
pattern = '^\d+$'           
txt = re.findall(pattern,msg)      # 传回搜寻结果
print(txt)
# 测试2搜寻开始或结尾皆是数字的字符串
msg = '0928tuyr990'
pattern = '^\d+$'
txt = re.findall(pattern,msg)      # 传回搜寻结果
print(txt)

执行结果

['09282028222']
[]

16-5-6 单一字符使用通配符“.”

通配符(wildcard)“.”表示可以搜寻除了换行字符以外的所有字符,但是只限定一个字符。

程序实例ch16_30.py:通配符的应用,搜寻一个通配符加上at,在下列输出中,第4个由于at符合,Python自动加上空格符。第6个由于只能加上一个字符,所以搜寻结果是lat。

# ch16_30.py
import re
msg = 'cat hat sat at matter flat'
pattern = '.at'           
txt = re.findall(pattern,msg)      # 传回搜寻结果
print(txt)

执行结果

['cat', 'hat', 'sat', ' at', 'mat', 'lat']

如果搜寻的是真正的“.”字符,须使用反斜杠“.”。

16-5-7 所有字符使用通配符“.*”

若是将16-3-7小节所介绍的“.”字符与“*”组合,可以搜寻所有字符,意义是搜寻0到多个通配符(换行字符除外)。

程序实例ch16_31.py:搜寻所有字符“.*”的组合应用。

# ch16_31.py
import re

msg = 'Name: Jiin-Kwei Hung Address: 8F, Nan-Jing E. Rd, Taipei'
pattern = 'Name: (.*) Address: (.*)'
txt = re.search(pattern,msg)      # 传回搜寻结果
Name, Address = txt.groups()
print("Name:    ", Name)
print("Address: ", Address)

执行结果

Name:     Jiin-Kwei Hung
Address:  8F, Nan-Jing E. Rd, Taipei

16-5-8 换行字符的处理

使用16-5-7小节观念用“.*”搜寻时碰上换行字符,搜寻就停止。Python的re模块提供参数re.DOTALL,功能是包括搜寻换行字符,可以将此参数放在search( )、findall( )或compile( )。

程序实例ch16_32.py:测试1是搜寻除换行字符以外的字符,测试2是搜寻含换行字符的所有字符。由于测试2有包含换行字符,所以输出时,换行字符主导分2行输出。

# ch16_32.py
import re
#测试1搜寻除了换行字符以外字符
msg = 'Name: Jiin-Kwei Hung \nAddress: 8F, Nan-Jing E. Rd, Taipei'
pattern = '.*'
txt = re.search(pattern,msg)           # 传回搜寻不含换行字符结果
print("测试1输出: ", txt.group())
#测试2搜寻包括换行字符
msg = 'Name: Jiin-Kwei Hung \nAddress: 8F, Nan-Jing E. Rd, Taipei'
pattern = '.*'
txt = re.search(pattern,msg,re.DOTALL) # 传回搜寻含换行字符结果
print("测试2输出: ", txt.group())

执行结果

测试1输出:  Name: Jiin-Kwei Hung 
测试2输出:  Name: Jiin-Kwei Hung
Address: 8F, Nan-Jing E. Rd, Taipei

16-6 MatchObject对象

16-2节已经讲解使用re.search( )搜寻字符串,搜寻成功时可以产生MatchObject对象,这里将先介绍另一个搜寻对象的方法re.match( ),这个方法搜寻成功后也将产生MatchObject对象。接着本节会分成几个小节,再讲解MatchObject几个重要的方法(method)。

16-6-1 re.match( )

这本书已经讲解了搜寻字符串中最重要的2个方法re.search( )和re.findall( ),re模块另一个方法是re.match( ),这个方法其实和re.search( )相同,差异是re.match( )只搜寻比对字符串开始的字,如果失败就算失败。re.search( )则是搜寻整个字符串。至于re.match( )搜寻成功会传回MatchObject对象,若是搜寻失败会传回None,这部分与re.search( )相同。

程序实例ch16_33.py:re.match( )的应用。测试1是将John放在被搜寻字符串的最前面,测试2没有将John放在被搜寻字符串的最前面。

# ch16_33.py
import re
#测试1搜寻使用re.match()
msg = 'John will attend my party tonight.'  # John是第一个字符串
pattern = 'John'
txt = re.match(pattern,msg)                 # 传回搜寻结果
if txt != None:
    print("测试1输出: ", txt.group())
else:
    print("测试1搜寻失败")
#测试2搜寻使用re.match()
msg = 'My best friend is John.'             # John不是第一个字符串
txt = re.match(pattern,msg,re.DOTALL)       # 传回搜寻结果
if txt != None:
    print("测试2输出: ", txt.group())
else:
    print("测试2搜寻失败")

执行结果

测试1输出:  John
测试2搜寻失败

16-6-2 MatchObject几个重要的方法

当使用re.search( )或re.match( )搜寻成功时,会产生MatchOjbect对象。

程序实例ch16_34.py:看看MatchObject对象是什么。

# ch16_34.py
import re
#测试1搜寻使用re.match()
msg = 'John will attend my party tonight.'  
pattern = 'John'
txt = re.match(pattern,msg)                 # re.match()
if txt != None:
    print("使用re.match()输出MatchObject对象:  ", txt)
else:
    print("测试1搜寻失败")
#测试1搜寻使用re.search()
txt = re.search(pattern,msg)                # re.search()
if txt != None:
    print("使用re.search()输出MatchObject对象: ", txt)
else:
    print("测试1搜寻失败")

执行结果

使用re.match()输出MatchObject对象:   <re.Match object; span=(0, 4), match='John'>
使用re.search()输出MatchObject对象:  <re.Match object; span=(0, 4), match='John'>   

从上述可知,当使用re.match( )和re.search( )皆搜寻成功时,两者的MatchObject对象内容是相同的。span是注明成功搜寻字符串的起始位置和结束位置,从此处可以知道起始索引位置是0,结束索引位置是4。match则是注明成功搜寻的字符串内容。

Python提供下列取得MatchObject对象内容的重要方法。

在这里插入图片描述

程序实例ch16_35.py:分别使用re.match( )和re.search( )搜寻字符串Joah,成功搜寻到字符串时,分别用start( )、end( )和span( )方法列出字符串出现的位置。

# ch16_35.py
import re
#测试1搜寻使用re.match()
msg = 'John will attend my party tonight.'  
pattern = 'John'
txt = re.match(pattern,msg)                 # re.match()
if txt != None:
    print("搜寻成功字符串的起始索引位置 :  ", txt.start())
    print("搜寻成功字符串的结束索引位置 :  ", txt.end())
    print("搜寻成功字符串的结束索引位置 :  ", txt.span())
#测试2搜寻使用re.search()
msg = 'My best friend is John.'  
txt = re.search(pattern,msg)                # re.search()
if txt != None:
    print("搜寻成功字符串的起始索引位置 :  ", txt.start())
    print("搜寻成功字符串的结束索引位置 :  ", txt.end())
    print("搜寻成功字符串的结束索引位置 :  ", txt.span())

执行结果

搜寻成功字符串的起始索引位置 :   0
搜寻成功字符串的结束索引位置 :   4
搜寻成功字符串的结束索引位置 :   (0, 4)
搜寻成功字符串的起始索引位置 :   18
搜寻成功字符串的结束索引位置 :   22
搜寻成功字符串的结束索引位置 :   (18, 22)

16-7 抢救CIA情报员-sub( )方法

Python re模块内的sub( )方法可以用新的字符串取代原本字符串的内容。

16-7-1 一般的应用

sub( )方法的基本使用语法如下:

 result = re.sub(pattern, newstr, msg)  # msg是整个欲处理的字符串或句子

pattern是欲搜寻的字符串,如果搜寻成功则用newstr取代,同时成功取代的结果回传给result变量,如果搜寻到多个相同字符串,这些字符串将全部被取代,需留意原先msg内容将不会改变。如果搜寻失败则将msg内容回传给result变量,当然msg内容也不会改变。

程序实例ch16_36.py:这是字符串取代的应用,测试1是发现2个字符串被成功取代(Eli Nan被Kevin Thomson取代),同时列出取代结果。测试2是取代失败,所以txt与原msg内容相同。

# ch16_36.py
import re
#测试1取代使用re.sub()结果成功
msg = 'Eli Nan will attend my party tonight. My best friend is Eli Nan'  
pattern = 'Eli Nan'                 # 欲搜寻字符串        
newstr = 'Kevin Thomson'            # 新字符串
txt = re.sub(pattern,newstr,msg)    # 如果找到则取代
if txt != msg:                      # 如果txt与msg内容不同表示取代成功
    print("取代成功: ", txt)        # 列出成功取代结果
else:
    print("取代失败: ", txt)        # 列出失败取代结果
#测试2取代使用re.sub()结果失败  
pattern = 'Eli Thomson'             # 欲搜寻字符串        
txt = re.sub(pattern,newstr,msg)    # 如果找到则取代           
if txt != msg:                      # 如果txt与msg内容不同表示取代成功
    print("取代成功: ", txt)        # 列出成功取代结果
else:
    print("取代失败: ", txt)        # 列出失败取代结果

执行结果

取代成功:  Kevin Thomson will attend my party tonight. My best friend is Kevin Thomson
取代失败:  Eli Nan will attend my party tonight. My best friend is Eli Nan

16-7-2 抢救CIA情报员
社会上有太多需要保护当事人隐私权利的场合,例如,情报机构在内部文件不可直接将情报员的名字列出来,历史上太多这类实例造成情报员的牺牲,这时可以使用***代替原本的姓名。使用Python的正则表示法,可以轻松协助我们执行这方面的工作。这一节将先用程序代码,然后解析此程序。

程序实例ch16_37.py:将CIA情报员名字,用名字第一个字母和***取代。

# ch16_37.py
import re
# 使用隐藏文字执行取代
msg = 'CIA Mark told CIA Linda that secret USB had given to CIA Peter.'
pattern = r'CIA (\w)\w*'            # 欲搜寻FBI + 空一格后的名字        
newstr = r'\1***'                   # 新字符串使用隐藏文字
txt = re.sub(pattern,newstr,msg)    # 执行取代
print("取代成功: ", txt)            # 列出取代结果

执行结果

取代成功:  M*** told L*** that secret USB had given to P***.

上述程序第一个关键是第5行,这一行将搜寻CIA字符串外加空一格后出现不限长度的字符串(可以由英文大小写或数字或底线所组成)。观念是括号内的(\w)代表必须只有一个字符,同时小括号代表这是一个分组(group),由于整行只有一个括号所以知道这是第一分组,同时只有一个分组,括号外的\w表示可以有0到多个字符。所以(\w)\w相当于是1-多个字符组成的单字,同时存在分组1。

上述程序第6行的\1代表用分组1找到的第一个字母当作字符串开头,后面则是接在第一个字母后的字符。对CIA Mark而言所找到的第一个字母是M,所以取代的结果是M。对CIA Linda而言所找到的第一个字母是L,所以取代的结果是L***。对CIA Peter而言所找到的第一个字母是P,所以取代的结果是P***。

16-8 处理比较复杂的正则表示法

有一个正则表示法内容如下:
在这里插入图片描述

其实相信大部分的读者看到上述正则表示法,就想弃械投降了,坦白说的确复杂,不过不用担心,笔者将一步步解析,让事情变简单。

16-8-1 将正则表达式拆成多行字符串

在3-4-2小节笔者有介绍可以使用3个单引号(或是双引号)将过长的字符串拆成多行表达,这个观念也可以应用在正则表达式,当我们适当地拆解后,可以为每一行加上批注,整个正则表达式就变得简单了。若是将上述pattern,拆解成下列表示法,整个就变得简单了。
在这里插入图片描述

接下来笔者分别解释相信读者就可以了解了,第一行区域号码是2位数,可以接受有括号的区域号码,也可以接受没有括号的区域号码,例如,02或(02)皆可以。第二行是设定区域号码与电话号码间的字符,可以接受空格符或-字符当作分隔符。第三行是设定8位数数字的电话号码。第四行是分机号码,分机号码可以用ext或ext.当作起始字符,空一定格数,然后接受2-4位数的分机号码。

16-8-2 re.VERBOSE

使用Python时,如果想在正则表达式中加上批注,可参考16-8-1小节,必须配合使用re.VERBOSE参数,然后将此参数放在search( )、findall( )或compile( )。

程序实例ch16_38.py:搜寻市区电话号码的应用,这个程序可以搜寻下列格式的电话号码。
在这里插入图片描述

# ch16_38.py
import re

msg = '''02-88223349, (02)-26669999, 02-29998888 ext 123,
        12345678, 02 33887766 ext. 12222'''
pattern = r'''(
    (\d{2}|\(\d{2}\))?              # 区域号码
    (\s|-)?                         # 区域号码与电话号码的分隔符
    \d{8}                           # 电话号码
    (\s*(ext|ext.)\s*\d{2,4})?      # 2-4位数的分机号码
    )'''
phoneNum = re.findall(pattern, msg, re.VERBOSE)     # 传回搜寻结果
print(phoneNum)

执行结果

[('02-88223349', '02', '-', '', ''), ('(02)-26669999', '(02)', '-', '', ''), ('02-29998888 ext 123', '02', '-', ' ext 123', 'ext'), (' 12345678', '', ' ', '', ''), ('02 33887766 ext. 1222', '02', ' ', ' ext. 1222', 'ext.')]

16-8-3 电子邮件地址的搜寻

在字处理过程中,必须在文件内将电子邮件地址解析出来很常见,下列是这方面的应用。下列是Pattern内容。

在这里插入图片描述

第1行用户账号常用的有a-z字符、A-Z字符、0-9数字、底线_、点.。第2行是@符号。第3行是主机域名,常用的有a-z字符、A-Z字符、0-9数字、分隔符-、点.。第4行是点 . 符号。第5行最常见的是com或edu,也可能是cc或其他,这通常由2至4个字符组成,常用的有a-z字符、A-Z字符。第6行是点 . 符号,在美国通常只要前5行就够了,但是在其他国家则常常需要此字段,所以此字段后面是?字符。第7行通常是国别,例如中国是cn、日本是ja,常用的有a-z字符、A-Z字符。

程序实例ch16_39.py:电子邮件地址的搜寻。

# ch16_39.py
import re

msg = '''txt@deepstone.com.tw kkk@gmail.com'''
pattern = r'''(
    [a-zA-Z0-9_.]+                  # 使用者账号
    @                               # @符号
    [a-zA-Z0-9-.]+                  # 主机域名domain
    [\.]                            # .符号
    [a-zA-Z]{2,4}                   # 可能是com或edu或其它
    ([\.])?                         # .符号, 也可能无特别是美国
    ([a-zA-Z]{2,4})?                # 国别
    )'''
eMail = re.findall(pattern, msg, re.VERBOSE)     # 传回搜寻结果
print(eMail)

执行结果

[('txt@deepstone.com.tw', '', ''), ('kkk@gmail.com', '', '')]

16-8-4 re.IGNORECASE/re.DOTALL/re.VERBOSE

在16-3-9小节笔者介绍了re.IGNORECASE参数,在16-5-8小节笔者介绍了re.DOTALL参数,在16-8-2小节笔者介绍了re.VERBOSE参数,我们可以分别在re.search( )、re.findall( )、re.match( )或是re.compile( )方法内使用它们,可是一次只能放置一个参数,如果我们想要一次放置多个参数特性,应如何处理?方法是使用16-3-4小节的管道|观念,例如,可以使用下列方式:

 datastr = re.search(pattern, msg, re.IGNORECASE|re.DOTALL|re.VERBOSE)

其实这一章已经讲解了相当多的正则表达式的知识了,未来各位在写论文、做研究或职场上相信会有相当帮助。如果仍觉不足,可以自行到Python官网获得更多正则表达式的知识。

在这里插入图片描述

从原理到接法全面了解三相电 阅读详情

相关推荐

STM32驱动四位共阳极数码管实现高精度秒表计时器

本文详细介绍了如何使用STM32驱动四位共阳极数码管实现高精度秒表计时器。项目基于STM32F103C8T6最小系统板,通过定时器中断和GPIO控制,实现0.1秒精度的计时功能,并解析了共阳极数码管的动态扫描原理及按键消抖等关键技术。

n8m7b6v5c4的博客 951

Python基础:正则表达式(regular expression)详解

在Python中,正则表达式是一种强大的工具,可用于匹配和操作字符串。什么是正则表达式?正则表达式是一种模式匹配语言,用于匹配字符串中的特定模式。这些模式可以是字母、数字、字符组合或其他符号。正则表达式通常用于文本处理、网络编程、数据分析等领域。在 Python 中,正则表达式的实现主要基于 re 模块,该模块提供了一组函数和类,用于处理正则表达式的匹配、搜索和替换。

Snailandfish的专栏 1035

让 AI 变聪明的 20 条指令:如何让大模型回答得更精准、更专业、更实事求是

让 AI 变聪明,本质上不是写几句神奇咒语,而是把你的任务表达得更清楚,把事实标准设得更严格,把输出格式规定得更明确,把不确定性管理得更认真,把历史对话利用得更充分。大模型的强项是语言生成、信息组织、模式归纳和方案扩展;弱项是事实核验、实时更新、责任判断和对模糊意图的准确猜测。好的指令,就是在用人的判断弥补模型的弱点,让模型把强项发挥在正确的地方。

Sumarua的博客 1495

Python正则表达式

Python正则表达式 正则表达式(Regular Expression,简写为regex)是“描述某种规则的表达式”的意思。换句话,正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。 Python 自1.5版本起增加了re 模块,re 模块使 Python 语言拥有全部的正则表达式功能。re库,这是一个Python处理文本的标准库。标准库的意思表示这是一个Python内置模块,不需要下载安装,

cnds123的专栏 2204

光学系统设计:波段、光源、光纤与探测器匹配指南

在光学测量和光纤通信系统中,波段、光源、光纤和探测器的匹配关系是系统设计的核心基础。波段指电磁波谱中的特定波长范围,光源负责产生特定波长的光信号,光纤作为传输介质需要与波长匹配以降低损耗,探测器则负责将光信号转换为电信号。理解各组件的光谱特性对于系统性能至关重要,例如在850nm短波长多模光纤系统中,VCSEL激光器与PIN光电二极管的组合能提供最佳性价比。典型应用场景包括生物医学成像、光纤通信和气体传感,其中光谱重叠优化、模场直径匹配和偏振特性协调是关键技术要点。通过实测数据对比不同组合的传输性能,可以为

weixin_33812433的博客 338

山景BP10_128DBG开发板ADC_Key驱动

最近在学习山景BP10_128DBG开发板,想使用开发板上的按键。看了看原理图和之前用过的按键好像有点不一样。常见的按键都是判断IO口是否被拉低或拉高来判断按键是否被按下。山景BP10_128DBG开发板上的按键是ADC按键,每个按键按下之后ADC的采样值是不同的,通过ADC采样回来的值进而判断哪个按键按下。这种方式核心思想就是用一个ADC通道来节约IO口,对于IO紧张的芯片是一个不错的解决思路。

weixin_56646002的博客 1311

Python正则表达式匹配电话号码和邮箱实例演示,正则表达式的基本用法

Python 正则表达式的基本用法 匹配邮箱地址 匹配电话号码 用法1:字符匹配 用法2:重复匹配 用法3:边界匹配 用法4:分组匹配 总结 正则表达式是一种文本模式匹配的工具,它用于描述一种字符组成的规则。在文本处理中,正则表达式被广泛用于搜索、替换、匹配、验证等操作。首先举两个正则表达式匹配的实例,然后再简单介绍一下正则表达式的基本用法。

小蓝枣的博客 3557

浙政钉(专有钉钉)门户免登(超详细)

钉钉家族 介绍浙政钉门户免登之前,首先搞清楚几个软件的关系,软件分别是:钉钉,专有钉钉,浙政钉 钉钉 是阿里巴巴集团专为中小企业打造的沟通和协同的多端平台。 专有钉钉 原名 政务钉钉,有更开放的设计能力、集成能力、更结构化协同产品、更定制化开发平台。支持专有化部署,数据落本地,更安全、客户可对该产品持牌运营、结构化编排,协助构建本地应用中心、提供移动应用全面安全保障体系。 浙政钉 为规范浙政钉整体架构体系,按照统分结合原则,由省政府办公厅统一设计整体工作界面和系统框架,统筹指导全省统建应用建设,各单

一缕南风的博客 2万+

Python -- 正则表达式 regular expression

正则表达式(regular expression) 根据其英文翻译,re模块 作用:用来匹配字符串。在Python中,正则表达式是特殊的字符序列,检查一个字符串是否与某种模式匹配。 设计思想:用一种描述性的语言来给字符串定义一个规则,凡是符合规则的字符串,就认为它“匹配”了,否则,该字符串就是不合法的。 格式:正则表达式也是用字符串表示的,...

weixin_30782293的博客 285

SpringBoot集成MinIO依赖冲突问题

场景一: 使用minio8.3.0版本的依赖,报下列异常: An attempt was made to call a method that does not exist. The attempt was made from the following location: io.minio.S3Base.<clinit>(S3Base.java:105) The following method did not exist: okhttp3.Requ...

qq_39974348的博客 1万+

AMBA-CHI协议详解(三)

Write Transactions、Atomic transactions、 Stash transactions、 Dataless transactions的等各个事务的事务流。

Crazzy_M的博客 3180

Python正则表达式详解(含丰富案例)

正则表达式在网络爬虫、数据分析中有着广泛使用,掌握正则表达式能够达到事半功倍的效果。本文详细介绍正则表达式中各种规则及其符号含义,并结合Python中的Re库进行演示,由浅入深,即学即练即用,内容丰富,非常适合初学者。正则表达式(regular expression)就是用一组由字母和符号组成的“表达式”来描述一个特征,然后去验证另一个“字符串”是否符合这个特征。比如表达式“xy+” 描述的特征是“一个 ‘x’ 和 至少一个 ‘y’ ”,那么‘xy’,‘xyy’, ‘xyyyyyyy’都符合这个特征。

Python栈 1万+

RAG测评实战代码

本文主要介绍了RAG测评实战代码,希望对使用RAG的同学们有所帮助。 文章目录 1. 前言 2. 实战代码 2.1 实战代码一 2.2 实战代码二

herosunly的博客 1万+

Python Regular Expression——简介

1. 正则表达式使用的特殊符号和字符 记号 说明 正则表达式样例 literal 匹配字符串的值 foo re1 | re2 匹配正则表达式re1或re2 foo | bar . 匹配任何字符(换行符除外) b.b ^

TheMinority的专栏 4415

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

【python】8个案例让你搞懂正则表达式regular expression

大家可以去这个网站学习正则表达式,对于这些案例的答案是没有标准答案的,其他答案也可以得到结果,以下只是我的思路。抛出异常的格式:at package.class.methodname(filename:linenumber)邮件地址:name+filter@domain,name主机名,domain域名,+filter有些地址没有。匹配字符串: ^-?其中port有时候是没有的。

lele_ne的博客 918

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

python学习笔记16(Regular Expressions正则表达式)

Charpter11 Regular Expressions(正则表达式) 知识点1: 关于正则表达式(Regular Expressions) 正则表达式是一种为匹配文本字符串提供的一种简洁而灵活的方法。正则表达式可以被正则表达式处理器解释。 关于python的正则表达式: 正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。 Python 自1.5版本起增加了re...

weixin_43593303的博客 373

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

python正则表达式——re模块的使用

python正则表达式——学习re模块 本文所有的代码使用的python版本为python3.5.1,运行环境为Ubuntu 16.04 LTS, GCC 5.3.1. 本文参考的python文档版本为python3.5.2,强烈建议英语不错的同学直接读文档。这篇博客只是作者阅读文档时的学习笔记,若有纰漏请指出,让我们共同进步。正则表达式基础介绍正则表达式正则表达式re是python自带的模块,

大音希声大象无形 1万+

小白python爬虫学习3(regular expression正则表达式RE)-淘宝商品,股票实例

依旧这些代码来自北理课程,之后会解释与学习相关知识 一:获取淘宝的商品与价格的代码: import requests import re def getHTMLText(url): try: r = requests.get(url, timeout=30) r.raise_for_status() r.encoding = r.apparent_encoding return r.text except:

qq_40533899的博客 482

数据清洗--2. regular expression 正则表达

数据清洗–2. regular expression 正则表达 目录数据清洗--2. regular expression 正则表达前言一、正则表达是什么二、正则表达能干什么三、正则表达的语法字母候选集(Character sets)字母候选域(Character ranges)反字母候选集(Negative character sets)特殊字符在候选集内(Metacharacters inside character sets)重复元字符(Repetition Expressions)字符组(Grou

Alvin3411的博客 535

在线常用正则表达式可视化生成与测试工具与示例 Regular Expression

在线常用正则表达式可视化生成与测试工具 Regular Expression

SAP ABAP PO PI 银企直连 1064

Regular Expressions 正则表达式及re模块の拾遗

1、Regular Expressions 与 python 渊源 正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合。 正则表达式就是字符串的匹配规则,在多数编程语言里都有相应的支持,python里对应的模块是re 正则表达式本身也和python没有什么关系,就是匹配字符串内容的一种规则 2、正则表达式 在线正则工具:http://tool.chinaz.com/regex/ 2.1 字符集 字符组 : [字符组] 在同一个位置可能出现的各种字符组成了一

Sunny_Future的博客 658

Python正则表达式(regular expression)简介-re模块

              Python正则表达式(regular expression)简介-re模块                                       作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任。     就其本质而言,正则表达式(或RE模块)是一种小型的,高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过re模块实现。正则表...

weixin_33739627的博客 273

还没搞懂正则?熬夜到虚脱整理出来的Python的正则表达式总结(Regular Expression)

re.M 多行匹配,影响 ^ 和 $re.S 使 . 匹配包括换行在内的所有字符re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。‘’’import reparrtern=‘…’#匹配规则,这里匹配两个字符print(res.group())#输出:py‘’‘测试二’‘’names=‘运智在学习python’,‘运气’,‘换人’

2401_84692382的博客 461

Python re module (regular expressions)

regular expressions (RE) 简介   re模块是python中处理正在表达式的一个模块 1 r"""Support for regular expressions (RE). 2 3 This module provides regular expression matching operations similar to 4 those ...

weixin_30662109的博客 513

python_Note_Preview_02_Regular Expression

Regular Expression 1 Str = 'BDefe 129032323 23322d3' 2 3 mr = re.search(r'[1-9]\d{5}', Str)   #只匹配第一个位置。 4 if mr: 5 print(type(mr)) 6 print(mr.groups) 7 ...

weixin_30726161的博客 89

Python正则表达式实战:从混杂文本中提取结构化信息

正则表达式是处理字符串匹配与提取的核心技术,通过定义特定模式,它能高效地从非结构化文本中定位和捕获目标信息。其技术价值在于将杂乱无章的原始数据转化为程序可读、可操作的结构化数据,极大地提升了数据清洗和信息抽取的自动化程度。在数据处理、日志分析、网络爬虫以及自然语言处理等应用场景中,正则表达式都是不可或缺的工具。本文以Python为例,结合【正则表达式】和【字符串处理】技术,详细演示了如何从混合了中英文、数字和日期的复杂字符串中,精准提取出如活动名称、类型和日期等关键字段,并输出为JSON格式,为构建可复用的

weixin_30731305的博客 309
上一篇: 我心中的王者:Python-第15章 程序除错与异常处理
下一篇: 我心中的王者:Python-第17章 使用Python处理Word文件
andyyah晓波
博客等级 码龄7年 3368粉丝 454原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值