玩转python之正则表达式

python正则表达式

    这篇博客主要记录自己在python学习中正则表达式的内容,主要是以下四个内容:

  • 简介/动机
  • 正则表达式字符
  • python中使用正则表达式
  • 几点特别说明

简介/动机

正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些匹配某个模式的文本。—— [ 维基百科 ]

    一句话来讲,正则表达式就是要实现对文本(一般来讲,就是字符串)的处理,包括添加、删除、分离、叠加、插入等各种操作。比如解决下面场景中的一些问题

  • 检索某台web服务器上的重复单词
  • 筛选出你的所有邮件中具有特定主题的邮件,进行其他操作(删除、转发)。

正则表达式字符

    正则表达式的字符是由普通字符(纯文本)或元字符(具有特殊含义的特殊字符)组成的;正则表达式的一个术语名称是模式(pattern)

符号说明
.匹配任意单个字符,(换行符\n除外)
匹配0次或1次前面出现的正则表达式
*匹配0次或多次前面出现的正则表达式
+匹配1次或多次前面出现的正则表达式
^匹配字符串的起始部分
$匹配字符串终止部分
re1 | re2匹配正则表达式re1 或re2
{ N }匹配n次前面出现的正则表达式
{M, N}匹配M~N次前面出现的正则表达式
[ ]匹配来自字符集的任意单一字符
[x-y]匹配x~y范围中的任意单一字符
[^ ]不匹配字符集出现的任何一个字符,包括某一范围的字符
( )匹配封闭的正则表达式,然后另存为子组


    下表是由 \和字母组成的特殊字符

表示法描述同义替换
\d匹配任何十进制数字[0-9]
\D匹配非数字
\w匹配任何字母数字字符[0-9A-Za-z]
\W与\w相反
\s匹配任何空格字符 \S与之相反[\n\t\r\v\f]
\b匹配任何单词边界\B与之相反
\A匹配字符串开始^
\Z匹配字符串的结尾$


    还有一些是扩展表示法

表示法描述示例
(?P < name>)由name标识的正则分组匹配

注:扩展表示法相对而言比较难以理解,解释晦涩。

    接下来对上表中的一些正则表达式用法做一个具体的解释。利用上表的正则表达式语法实现具体的功能。

从字符串起始或者结尾或者单词的边界匹配

    用于实现该功能的正则表达式有 ^ 、 \A 、 $ 、\Z、 \b、 \B ,其中 ^ 和 \A实现从字符串的开始位置进行匹配; $ 和 \Z 用于匹配字符串的末尾位置。特殊字符\b实现匹配字符边界,\B与之相反;下面是一些示例

正则表达式模式匹配的字符串
^From任何以From作为起始字符串的字符串
end$任何以end作为结尾的字符串
\bthe任何以the开始的字符串
\bthe\b仅仅匹配单词the
\Bthe包含但不以the作为起始的字符串

字符集的功能

    利用字符集可以实现以下功能:

  • 匹配方括号中任意一个字符
  • 匹配指定的字符范围(方括号中两个符号中间用-连接)
  • 不匹配给定字符集中的任何一个字符(^紧跟在左方括号后面)

正则表达式模式匹配的字符串
b[ai]tbat 、bit
z.[0-9]z后面跟着任何一个字符,然后跟一个数字
[^\t\n]不匹配制表符或者\n

使用圆括号指定分组

    一对圆括号可以实现以下两个功能:

  • 对正则表达式进行分组(重复操作符,而不是单一字符或者字符集)
  • 匹配子组(实现分别访问每一个子组)

python中使用正则表达式

    python中为了利用正则表达式实现对字符串的处理,提供了一些函数,这些函数被封装在re模块中,下面是re模块的常用的核心函数和方法

函数名称功能备注
compile(pattern,flags =0)使用可选的标记编译正则表达式模式,返回一个正则表达式对象仅仅是re模块函数
search(pattern,string,flags = 0)搜素字符串中第一次出现的正则表达式模式,返回匹配对象re模块函数和正则表达式对象的方法
match(pattern,string,flags = 0)从头开始匹配,,返回匹配对象同上
findall (pattern,string [,flags])把所有匹配到的字符放到以列表中的元素返回同上
finditer(pattern,string [,flags])与findall函数相同,但返回的是一个迭代器同上
split(pattern,string ,max = 0)根据正则表达式的模式进行分割,返回一个列表 ,分割最多操作max次,默认分割所有匹配成功的函数同上
sub (pattern,repl,string,count = 0)使用repl替换所有正则表达式的模式在字符串中出现的位置,除非定义count,否则就替换所有出现的位置同上
group (num =0)返回整个匹配对象,或者编号为num的特定子组匹配对象(如match、search返回的对象)的方法
groups返回一个包含所有匹配对象的元组同上
groupdict返回一个包含有所有匹配的命名子组的字典,所有的子组名称作为字典的键值同上
re.I不区分大小写的匹配模块属性
re.M多行匹配模块属性
re.S匹配全部的字符 包含换行符模块属性

注:红色标注的为重点需掌握的内容。


    下面通过代码来演示如何使用re模块

compile 演示

    在模式发生匹配之前,正则表达式模式必须编译成正则表达式对象。因此如果在比较之前提前对正则表达式模式进行编译(预编译过程),可以提高程序的运行效率,re模块的compile函数提供了对正则表达式进行编译的功能,编译后,返回一个正则表达式对象,这也是为什么一开始就介绍compile函数的意图。

import re
# 使用compile进行预编译和不使用该函数时的一个例子
obj = re.compile('\.com')   # 对正则表达式进行编译,返回的正则表达式对象可以被多次调用

ret = obj.search('xxx.com')
print(ret)   # <_sre.SRE_Match object; span=(3, 7), match='.com'>
print(ret.group()) # group 返回匹配对象
ret_1 = re.search('\.com', 'xxx.com')
print(ret_1)
print(ret_1.group())

    运行结果展示:

compile函数演示

match和search比较

     match和search最大的区别在于search在任意位置进行搜索匹配,而match必须从开头进行匹配。

import re
# 使用match、search的例子
str = 'food on the table'
str_1 = 'the man is fool'
m = re.match('foo', str)
m_1 = re.match('foo', str_1)  # match 无法匹配到 ,match只能从起始位置匹配
m_2 = re.search('foo', str_1)  # search 可以匹配到
if m is not None : print('print m', m.group())
if m_1 is not None : print('print m_1', m_1.group())
if m_2 is not None : print('print m_2', m_2.group())

    运行结果展示:

match和search比较

findall 、finditer和sub 使用

     findall 和 finditer的区别在于返回对象不同,findall 返回一个列表;finditer返回一个迭代器对象。

import re
# findall finditer sub 示例
str = 'this and thatis'
ret_findall = re.findall('th\w+', str)  # 在这个示例中,将匹配字符串中this 和 that 并且以列表的形式返回
ret_finditer = re.finditer('th\w+',str) # 功能同上,返回迭代器
ret_sub = re.sub('th\w+','good',str)    # 用good 对 this和 that进行替换
print(ret_findall)
print(next(ret_finditer).group())       # 利用next对迭代器对象区取值
print(next(ret_finditer).group())
print(ret_sub)

运行结果如下:
findall示例

分组及group、 groups比较使用

    使用()可以用来保存分组,以便于后续处理,使用group方法访问每个独立的子组以及groups()方法获取一个包含所有匹配子组的元组

import re
# 分组示例
m_group = re.match('(\w\w\w)-(\d\d\d)', 'abc-123')
print(m_group.group())   # 完整匹配
print(m_group.group(1))  # 子组1
print(m_group.group(2))  # 子组2
print(m_group.groups())  # 全部子组

    运行结果如下:

groups和group区别

split的一个复杂例子

re模块的split()方法和string自带的split方法是类似的,但更为强大和灵活。下面是一个较为复杂的例子,一个用于web站点的简单解释器,用户输入城市名和州名 ,或者城市名加上ZIP码(5个数字),三者不一定全部都有。

import re
# split复杂例子

DATA = ('Mountain View,CA 94040',
        'Sunnyvale CA',
        'Los Altos,94023',
        'Cupertino 95014',
        'Palo Alto CA')

for datun in DATA:
    print(re.split(',|(?= (?:\d{5}|[A-Z]{2})) ',datun))

    运行结果如下:

split例子

    注:对这个例子中出现的扩展字符的用法理解的还不是很透彻

正则表达式在python中的示例

几点特别的说明

搜索匹配与贪婪

    正则表达式本质上实现贪婪匹配,这就意味着对于通配符模式,将对正则表达式从左向右的顺序求值,而且试图获取匹配该模式尽可能多的字符。
    使用非贪婪操作符?,在* + ?使用该操作符。该操作符要求正则表达式匹配尽可能少的字符。

使用python原始字符(转义字符\的问题)

    我们知道,可以用\n表示换行,用\d表示表示匹配的单个数字。如果有符号同时用于ASCII和正则表达式,就会产生问题,因此可以利用python原始字符串来避免这种问题,即在正则表达式模式前加r。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值