正则表达式(三):python re模块

以下示例所使用 python 版本为: 3.7

python 提供 re 模块,来满足正则表达式的使用。在开始介绍 re 模块之前,首先说明一下两个小内容:

  1. 转义字符 \

转义字符作用是使得字符失去原本的意思,去表示另外一个作用。例如字符 d 表示一个普通的字符 d, 加 \ 转义后 \d 表示数字,字符 s 经转义后,\s 表示空白字符。

如果要匹配转义符号 \ 本身,则需要表达为 \\ 。而在编程语言中要表达两个转义符号 \\,则需要对每个转义符号进行转义,即形式为 \\\\,需要四个转义符号才能完成用于匹配一个转义符号 \ 的正则表达式。

为了减弱转义字符使用上的麻烦,能够将使用者的注意力集中在正则表达式的编写上,这里推荐所有的正则表达式开头使用 r 字符开头,表示正则内容作为原始字符串输入到 re 模块的使用中。即编程环境中 r'\\' 直接作为正则表达式使用,来完成对字符 \ 的匹配。

示例:

import re

reg = r'\\'
str = '\\'    #转义符号,str实际值为\

if re.match(reg,str):
    print('match {}'.format(str))
------------------------
运行结果:
match \
  1. Pattern、Match对象

在re模块中使用正则表达式完成字符串处理有两种方式:

  • 在 python 中可以直接使用 re 模块生成 Match 对象,完成字符串处理。
    示例:
import re

reg = r'abc'
str = 'abc'

mattern = re.match(reg,str)
print(mattern .group())
------------------------
运行结果:
abc
  • 使用 re 模块生成 Pattern 对象,然后使用 Pattern 对象生成 Match 对象,完成字符串处理。
    示例:
import re

reg = r'abc'
str = 'abc'

pattern = re.compile(reg)
match = pattern.match(str)
print(match.group())
------------------------
运行结果:
abc

这两种方式执行效果基本一样,观察 re 模块源代码:

模块: \Python37\Lib\re.py

# --------------------------------------------------------------------
# public interface

def match(pattern, string, flags=0):          #第一种方式
    """Try to apply the pattern at the start of the string, returning
    a Match object, or None if no match was found."""
    return _compile(pattern, flags).match(string)

def compile(pattern, flags=0):                #第二种方式
    "Compile a regular expression pattern, returning a Pattern object."
    return _compile(pattern, flags)

# --------------------------------------------------------------------
# internals

_cache = {}  # ordered!

_MAXCACHE = 512
def _compile(pattern, flags):
    # internal: compile pattern
    if isinstance(flags, RegexFlag):
        flags = flags.value
    try:
        return _cache[type(pattern), pattern, flags]         #从缓存字典中查询
    except KeyError:
        pass
    if isinstance(pattern, Pattern):
        if flags:
            raise ValueError(
                "cannot process flags argument with a compiled pattern")
        return pattern
    if not sre_compile.isstring(pattern):
        raise TypeError("first argument must be string or compiled pattern")
    p = sre_compile.compile(pattern, flags)
    if not (flags & DEBUG):
        if len(_cache) >= _MAXCACHE:
            # Drop the oldest item
            try:
                del _cache[next(iter(_cache))]
            except (StopIteration, RuntimeError, KeyError):
                pass
        _cache[type(pattern), pattern, flags] = p         #添加到缓存字典中
    return p

观察源码可知, re 模块提供的 compile 函数和 match 函数,都需要先通过 _compile(pattern, flags) 函数生成一个 Pattern 对象,区别在于 match 函数直接在生成 Pattern 对象后调用了 match 函数。
观察 _compile(pattern, flags) 函数体可知,首先会从缓存字典中查询是否已经存在 Pattern 对象,存在则返回,不存在则生成该 Pattern 对象,添加到缓存字典后返回。

由此可知,直接使用 re 模块的 match 函数来生成 Match 对象,和使用 re 模块的 compile 函数生成 Pattern 对象,然后再利用 match 函数生成 Match 对象完成字符串处理,这两种方式都是首先调用 _compile(pattern, flags) 函数生成一个Pattern对象,然后再使用该 Pattern 对象的 match 函数生成 Match 对象。

所以两种方式基本相同,区别只在于当 Pattern 对象多次使用时,第一种方式会存在多次查询缓存操作,且缓存字典容量是有限制的,超出后会删除最先添加的 Pattern 对象,所以推荐所有的正则中都使用构造的 Pattern 对象来完成字符串处理。

下面列出 Pattern 对象中使用到的函数:
函数名 作用
match(string, pos=0, endpos=-1) 在指定范围内,从指定的起始位置开始匹配,得到匹配对象则返回
search(string, pos=0, endpos=-1) 在指定范围内,从任意位置开始匹配,得到匹配对象则返回
findall(string, pos=0, endpos=-1) 在指定范围内,返回所有匹配结果构成的列表
finditer(string, pos=0, endpos=-1) 在指定范围内,返回所有匹配对象构成的迭代器
split(string, maxsplit=0) 按照指定的分割次数,返回分割得到的结果列表
sub(repl, string, count=0) 按照指定的替换规则和替换次数,返回替换后的结果
subn(repl, string, count=0) 按照指定的替换规则和替换次数,返回替换后的结果和替换次数构成的元组
  • match 函数

match 函数返回指定范围内,从指定起始位置开始匹配到的对象。使用过程中只有三点需要注意一下:
1. 可以指定匹配的范围,默认范围是 0 到 len(str)
2. 匹配是从指定的起始位置开始的,也就是固定了开始位置
3. 匹配成功则返回,也就是只返回一个匹配对象

示例:

import re

reg = r'\d'
pattern = re.compile(reg)

str1 = 'a1b2c3'

match1 = pattern.match(str1)
match2 = pattern.match(str1,1)

print('match1 = {}'.format(match1))
if match1:
    print('match1 matched = {}'.format(match1.group()))

print('match2 = {}'.format(match2))
if match2:
    print('match2 matched = {}'.format(match2.group()))
运行结果:
match1 = None
match2 = <re.Match object; span=(1, 2), match='1'>
match2 matched = 1
  • search 函数

search 函数返回指定范围内,从任意起始位置开始匹配到的对象。使用过程中只有三点需要注意一下:
1. 可以指定匹配的范围,默认范围是 0 到 len(str)
2. 匹配是从范围内的任意起始位置开始的,也就是不固定开始位置
3. 匹配成功则返回,也就是只返回一个匹配对象

示例:

import re

reg = r'\d'
pattern = re.compile(reg)

str1 = 'a1b2c3'

match1 = pattern.search(str1)

print('match1 = {}'.format(match1))
if match1:
    print('match1 matched = {}'.format(match1.group()))
运行结果:
match1 = <re.Match object; span=(1, 2), match='1'>
match1 matched = 1

比较 match 和 search 函数的使用:两个函数都是一次匹配,得到结果则返回 (None 或 Match 对象),区别在于 match 函数从指定的起始位置开始匹配,search 函数从指定范围内的任意位置开始。

  • findall 函数

findall 函数返回指定范围内,所有匹配结果构成的列表。使用过程中只有两点需要注意一下:
1. 可以指定匹配的范围,默认范围是 0 到 len(str)
2. 返回的是一个列表,元素是 str 对象,而非 Match 对象

示例:

import re

reg = r'\d'
pattern = re.compile(reg)

str1 = 'a1b2c3'

match1 = pattern.findall(str1)

print('match1 = {}'.format(match1))
for element in match1:
    print('element = {}'.format(element))
运行结果:
match1 = ['1', '2', '3']
element = 1
element = 2
element = 3
  • finditer 函数

finditer 函数返回指定范围内,所有匹配对象构成的迭代器。使用过程中只有两点需要注意一下:
1. 可以指定匹配的范围,默认范围是 0 到 len(str)
2. 返回的是一个迭代器,元素是 Match 对象

示例:

import re

reg = r'\d'
pattern = re.compile(reg)

str1 = 'a1b2c3'

match1 = pattern.finditer(str1)

print('match1 = {}'.format(match1))
for element in match1:
    print('element = {}'.format(element.group()))
运行结果:
match1 = <callable_iterator object at 0x0000000002CA0550>
element = 1
element = 2
element = 3

比较 findall 和 finditer 函数的使用:两个函数都是获取所有匹配内容,区别在于 findall 函数返回的是一个列表,元素类型是 str,finditer 函数返回的是一个迭代器,元素类型是 Match 。

  • split 函数

split 函数返回根据指定分割次数,分割后得到的结果列表。使用过程中只有两点需要注意一下:
1. 可以指定分割次数,默认值 0 表示全分割
2. 返回的是一个列表,元素是 str 对象

示例:

import re

reg = r'\d'
pattern = re.compile(reg)

str1 = 'a1b2c3'

match1 = pattern.split(str1)

print('match1 = {}'.format(match1))
for element in match1:
    print('element = {}'.format(element))
运行结果:
match1 = ['a', 'b', 'c', '']
element = a
element = b
element = c
element = 
  • sub 函数

sub 函数根据指定替换规则和替换次数,返回替换后内容。使用过程中只有三点需要注意一下:
1. 可以指定替换次数,默认值 0 表示全替换
2. 返回的是一个 str 对象
3. 指定的替换规则可以是 str 对象,可以是一个函数,也可以是分组的引用

示例:

import re

def fun(match):
    return match.group()[::-1]

reg = r'(\d)(\d)'
pattern = re.compile(reg)

str1 = 'a12b34c56'

match1 = pattern.sub('__',str1)
match2 = pattern.sub(fun,str1)
match3 = pattern.sub(r'\2\1',str1)

print('match1 = {}'.format(match1))
print('match2 = {}'.format(match2))
print('match3 = {}'.format(match3))
运行结果:
match1 = a__b__c__
match2 = a21b43c65
match3 = a21b43c65
  • subn 函数

subn 函数根据指定替换规则和替换次数,返回替换后内容和替换次数构成的元组。使用过程中只有三点需要注意一下:
1. 可以指定替换次数,默认值 0 表示全替换
2. 返回的是一个 str 对象和 int 对象构成的元组
3. 指定的替换规则可以是 str 对象,可以是一个函数,也可以是分组的引用

示例:

import re

def fun(match):
    return match.group()[::-1]

reg = r'(\d)(\d)'
pattern = re.compile(reg)

str1 = 'a12b34c56'

match1 = pattern.subn('__',str1,1)
match2 = pattern.subn('__',str1,2)


print('match1 = {}'.format(match1))
print('match2 = {}'.format(match2))
运行结果:
match1 = ('a__b34c56', 1)
match2 = ('a__b__c56', 2)

比较 sub 和 subn 函数的使用:两个函数都是替换匹配内容,区别在于 sub 函数返回的是一个 str 对象,subn 函数返回的是替换后 str 对象和替换次数 int 对象构成的元组。

下面列出 Match 对象中常到的函数:
函数名 作用
group(*args) 返回指定的分组匹配的结果
groups(default=None) 返回所有分组匹配结果构成的元组
span(group=0) 返回由指定分组匹配结果区间的首尾两个下标值构成的元组
start(group=0) 返回指定分组匹配结果区间的首下标值
end(group=0) 返回指定分组匹配结果区间的尾下标值
  • group、groups、span、start、end 函数

以上这几个函数作为常用函数,使用方式较为简单:
1. group:返回指定分组匹配的内容,参数为零或者默认值时,返回整个正则表达式匹配结果;参数为多个分组时,返回分组匹配结果构成的元组
2. groups:返回分组匹配结果构成的元组
3. span:返回指定分组匹配结果区间的首尾两个下标值(左闭右开)构成的元组,默认情况下匹配整个正则表达式匹配结果的首尾两个下标值
4. start:返回指定分组匹配结果区间的首下标
5. end:返回指定分组匹配结果区间的尾下标

示例:

import re

reg = r'(\d)(\d)'
pattern = re.compile(reg)

str1 = 'a12b'

match1 = pattern.search(str1)

print('group 1 = {}'.format(match1.group(1)))
print('span 1 = {}'.format(match1.span(1)))
print('start 1 = {}'.format(match1.start(1)))
print('end 1 = {}'.format(match1.end(1)),end='\n\n')

print('group 2 = {}'.format(match1.group(2)))
print('span 2 = {}'.format(match1.span(2)))
print('start 2 = {}'.format(match1.start(2)))
print('end 2 = {}'.format(match1.end(2)),end='\n\n')

print('groups = {}'.format(match1.groups()))
print('span = {}'.format(match1.span()))
print('start = {}'.format(match1.start()))
print('end = {}'.format(match1.end()),end='\n\n')

print('group 1,2 = {}'.format(match1.group(1,2)))
运行结果:
group 1 = 1
span 1 = (1, 2)
start 1 = 1
end 1 = 2

group 2 = 2
span 2 = (2, 3)
start 2 = 2
end 2 = 3

groups = ('1', '2')
span = (1, 3)
start = 1
end = 3

group 1,2 = ('1', '2')
Pattern 用作模式处理,Match 用作分组结果提取

比较以上 Pattern 和 Match 两种对象的使用方式,可以发现 Pattern 对象作用如其名称所示,是一种体现正则表达式规则的对象,也就是体现为一种文本模式。其所提供的诸多函数,如: find、search、match 等等,都是拿自身的规则以不同的方式去处理目标文本。而 Match 对象则是对分组结果的操作,Match 对象提供的函数则都是对结果以不同方式的提取,如:groups、span等,获取匹配分组结果的各项数据。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,753评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,668评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,090评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,010评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,054评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,806评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,484评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,380评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,873评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,021评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,158评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,838评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,499评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,044评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,159评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,449评论 3 374
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,136评论 2 356

推荐阅读更多精彩内容

  • Python中的正则表达式(re) import rere.match #从开始位置开始匹配,如果开头没有则无re...
    BigJeffWang阅读 7,087评论 0 99
  • python的re模块--细说正则表达式 可能是东半球最详细最全面的re教程,翻译自官方文档,因为官方文档写的是真...
    立而人阅读 22,891评论 4 46
  • re模块手册 本模块提供了和Perl里的正则表达式类似的功能,不关是正则表达式本身还是被搜索的字符串,都可以...
    喜欢吃栗子阅读 4,010评论 0 13
  • #首先,python中的正则表达式大致分为以下几部分: 元字符 模式 函数 re 内置对象用法 分组用法 环视用法...
    mapuboy阅读 1,614评论 0 51
  • 前言 对于正则,著称火星文字,见名知意主要它晦涩难懂,一直以来,看到它总是怕怕的,在平时,也只是简单的用用,其主要...
    itclanCoder阅读 772评论 0 2