python正则表达式

正则表达式(regular expression),是匹配文本字段的模式。其设计思想是用一种描述性的语言来给字符串定义一个规则,凡是符合规则的字符串,我们就认为它“匹配”了,否则,该字符串就是不合法的。若想使用正则表达式处理字符串,必须使用支持正则表达式的工具。python提供了对正则表达式的支持。

下图展示了适用于python的正则表达式元字符及说明:

img

python提供re模块实现对正则表达式的支持。

1. re模块函数

1.1 match()函数

格式:re.match(pattern, string, flags=0)

  • 从字符串开头匹配,若匹配到就返回一个相应的匹配对象(match对象) 。 如果没有匹配,就返回 None。
  • pattern为正则表达式,string为要匹配的字符串。match()方法默认只匹配字符串开头(即从开头开始匹配)
  • 实际使用一般先判断是否返回match对象(是否成功匹配),再进行相关操作。

match对象支持以下方法:

  • Match.start() Match.end() Match.span() :分别返回匹配结果的开始索引,结束索引,整体索引。

  • Match.group([group1, ...])

    • 返回一个或者多个匹配到的结果。match对象内部存储了正则表达式匹配到的结果,并将每个分组匹配到的结果从1开始编号。
    • 如果只有一个参数,就只返回该分组对应的匹配结果(一个字符串);如果有多个参数,就返回多个参数对应的匹配结果组成的元组;若没有参数或者参数为0,会将整个匹配结果返回。
  • Match.groups(default=None):返回一个元组,包含每个分组匹配到的结果。

# 正则表达式:re.match()
import re

str1 = "one2two33four"
str2 = "12345..7890"

# 正则表达式:匹配两边若干个数字,中间若干个.组成的字符串
pattern = r"(\d+)\.*(\d+)"

# 返回匹配对象
result1 = re.match(pattern, str1
result2 = re.match(pattern, str2)


print(result1)  # 未匹配到返回None
print(result2)  # 匹配到返回match对象

print(result2.group())  # 返回正则表达式匹配到的结果
print(result2.group(0))  # 返回正则表达式匹配到的结果
print(result2.group(1, 2))  # 返回正则表达式中两个分组匹配到的结果(元组)
print(result2.group(1))  # 返回正则表达式中第一个分组匹配到的结果
print(result2.group(2))  # 返回正则表达式中第二个分组匹配到的结果
print(result2.groups())  # 返回正则表达式中每个分组匹配到的结果(元组)
                   
# 执行结果
None
<re.Match object; span=(0, 11), match='12345..7890'>
12345..7890
12345..7890
('12345', '7890')
12345
7890
('12345', '7890')              
1.2 search()函数

格式:re.search(pattern, string, flags=0)

  • 搜索整个字符串进行匹配,若匹配到就返回一个相应的匹配对象(match对象) 。 如果没有匹配,就返回 None。
  • 注意点:只会返回匹配到的第一个结果。
# 正则表达式:re.search()
import re

str1 = "one123...456seven789...345"

# 正则表达式:匹配匹配两边若干个数字,中间若干个.组成的字符串
pattern = r"(\d+)\.*(\d+)"

result = re.search(pattern, str1)
print(result)

print(result.group())
print(result.group(0))
print(result.group(1, 2)) 
print(result.group(1)) 
print(result.group(2)) 
print(result.groups()) 

# 执行结果
<re.Match object; span=(3, 12), match='123...456'>
123...456
123...456
('123', '456')
123
456
('123', '456')
1.3 findall()函数

格式:re.findall(pattern, string, flags=0)

  • 搜索整个字符串,返回正则表达式匹配到的所有结果组成的列表形式。
  • 如果正则表达式里面存在多个分组,则每个匹配到的结果是表达式中每个分组匹配到的字符串组成的元组形式。
# 正则表达式:re.findall()

import re

str1 = "123four567eight"
str2 = "one123...456seven789...345"


# 正则表达式
pattern1 = r"\d+"
pattern2 = r"(\d+)\.*(\d+)"

result1 = re.findall(pattern1, str1)
result2 = re.findall(pattern2, str2)
print(result1)
print(result2)

# 执行结果
['123', '567']
[('123', '456'), ('789', '345')]
1.4 sub()函数

格式:re.sub(pattern, repl, string, count=0, flags=0)

  • 使用表达式对字符串进行匹配,将每一个匹配到的结果使用repl进行替换,返回替换后的结果

  • 参数解析:

    • pattern:正则表达式;
    • repl:可为一个字符串或者函数;若为一个字符串,里面的转义字符会被处理(原始字符串除外);若为一个函数,该函数接收匹配到的对象为参数,返回一个替换后的字符串
    • repl也可使用\number形式引用分组匹配到的字符串进行替换
# 正则表达式:re.sub()
import re

def deal(matchobj):
    # 根据匹配结果的长度返回不同的替换字符串
    if len(matchobj.group()) <= 6:
        return "---------"
    else:
        return "*********"


str1 = "one12..56seven789...345"

# 正则表达式:此处会匹配到两个结果会对两个结果进行替换
pattern = r"(\d+)\.*(\d+)"

result1 = re.sub(pattern, "_replace_string_", str1)  # 使用字符串替换
result2 = re.sub(pattern, deal, str1)  # 使用函数处理替换
result3 = re.sub(pattern, r"\2 \1", str1)

print(result1)
print(result2)
print(result3)

# 执行结果
one_replace_string_seven_replace_string_
one---------seven*********
one56 12seven345 789
1.5 subn()函数

格式:re.subn(pattern, repl, string, count=0, flags=0)

  • 作用和sub()相似,返回一个元组(str, int),第一个元素为替换后的字符串,第二个为替换的次数
import re

result01 = re.subn(r'(\w+) (\w+)', r'hello world', 'hello 123, hello 456')
result02 = re.subn(r'(\w+) (\w+)', r'\2 \1', 'hello 123, hello 456')

print(result01)
print(result02)
# 结果
('hello world, hello world', 2)
('123 hello, 456 hello', 2)
1.6 split()函数

格式:re.split(pattern, string, maxsplit=0, flags=0)

  • 使用正则表达式匹配到的字符串进行分割,返回列表形式
  • 若正则表达式里面含有分组,则分组匹配到的字符也会包含在列表里面
# 正则表达式:re.split()
import re

str1 = "info:xiaoZhang 33 shandong"

pattern = r":| "

result = re.split(pattern, str1)
print(result)

# 执行结果
['info', 'xiaoZhang', '33', 'shandong']

2. 正则表达式对象的方法

可使用re.compile()函数将正则表达式编译为哟个正则表达式对象,然后使用对象的方法实现字符串匹配。

2.1 compile()函数

该函数用于编译正则表达式,形式如:re.compile(pattern, flags=0)。返回一个pattern对象。

  • 使用compile函数将正则表达式编译为一个pattern对象(模式)
  • 通过pattren对象提供的方法对文本进行匹配,获得匹配结果(一个match对象或None)
  • 利用match对象的属性和方法获得信息(匹配的子串,索引位置等)
2.2 match()方法

格式:pattern.match(string: AnyStr, pos: int = ..., endpos: int = ...)

  • pos和endpos参数指定匹配的范围即起始和结束位置。它是一次匹配,即找到了一个结果就返回,而不是查找所有的匹配结果。匹配成功时,返回一个match对象,否则返回None。
  • 实际使用一般先判断是否返回match对象(是否成功匹配),再进行相关操作。
# match()方法
import re

str1 = "12345..7890"
str2 = "zjbiafbia456....89764"

pattern = re.compile(r"(\d+)\.*(\d+)")
print(pattern)

result1 = pattern.match(str1)
result2 = pattern.match(str2, 9, 21)  # 制定匹配的范围
print(result1)
print(result2)

print(result1.start())  # 打印匹配结果的开始索引
print(result1.end())  # 打印匹配结果的结束索引
print(result1.group())  # 打印匹配的结果
print(result1.group(0))  # 打印匹配的结果
print(result1.group(1))  # 打印打印匹配结果中的第一个分组结果
print(result1.group(2))  # 打印打印匹配结果中的第二个分组结果

print(result2.group())
print(result2.group(0))
print(result2.group(1))
print(result2.group(2))

# 执行结果
re.compile('(\\d+)\\.*(\\d+)')
<re.Match object; span=(0, 11), match='12345..7890'>
<re.Match object; span=(9, 21), match='456....89764'>
0
11
12345..7890
12345..7890
12345
7890
456....89764
456....89764
456
89764
2.3 search()方法

格式:Pattern.search(string[, pos[, endpos]])

  • 搜索整个字符串,进行匹配,匹配到一个结果就返回。
  • pos和endpos参数指定匹配的范围即起始和结束位置。
# search()方法
import re

str1 = "one123...456seven789...345"

# 正则表达式:匹配匹配两边若干个数字,中间若干个.组成的字符串
pattern = re.compile(r"(\d+)\.*(\d+)")

result = pattern.search(str1)
print(result)

print(result.start())  # 返回匹配字符串的开始索引
print(result.end())  # 返回匹配字符串的结束索引
print(result.group())  # 返回正则表达式匹配到的结果
print(result.group(0))  # 返回正则表达式匹配到的结果
print(result.group(1, 2))  # 返回正则表达式中两个分组匹配到的结果(元组)
print(result.group(1))  # 返回正则表达式中第一个分组匹配到的结果
print(result.group(2))  # 返回正则表达式中第二个分组匹配到的结果
print(result.groups())  # 返回正则表达式中每个分组匹配到的结果(元组)

# 执行结果
<re.Match object; span=(3, 12), match='123...456'>
3
12
123...456
123...456
('123', '456')
123
456
('123', '456')
2.4 findall()方法

格式:Pattern.findall(string[, pos[, endpos]])

  • 搜索字符串内的所有符合正则表达式的子串,以列表形式返回。
  • pos和endpos参数指定匹配的范围即起始和结束位置。
# findall()方法
import re

str1 = "123four567eight"
str2 = "one123...456seven789...345"


# 正则表达式
pattern1 = re.compile(r"\d+")
pattern2 = re.compile(r"(\d+)\.*(\d+)")

result1 = pattern1.findall(str1)
result2 = pattern2.findall(str2)
print(result1)
print(result2)

# 执行结果
['123', '567']
[('123', '456'), ('789', '345')]
2.5 split()方法

格式:Pattern.split(string, maxsplit=0) 类似于re.split()方法,分割字符串。

# split()方法
import re

str1 = "info:xiaoZhang 33 shandong"

pattern = re.compile(r":| ")

result = pattern.split(str1)
print(result)

# 执行结果
['info', 'xiaoZhang', '33', 'shandong']
2.6 sub()方法
  • 使用字符串或函数返回的字符串替换pattern对象匹配到的字符串,等同于re.sub()函数。
# sub()方法
import re

def deal(matchobj):
    # 根据匹配结果的长度返回不同的替换字符串
    if len(matchobj.group()) <= 6:
        return "---------"
    else:
        return "*********"


str1 = "one12..56seven789...345"

# 正则表达式:此处会匹配到两个结果会对两个结果进行替换
pattern = re.compile(r"(\d+)\.*(\d+)")

result1 = pattern.sub("_replace_string_", str1)  # 使用字符串替换
result2 = pattern.sub(deal, str1)  # 使用函数处理替换
result3 = pattern.sub(r"\2 \1", str1)

print(result1)
print(result2)
print(result3)

# 执行结果
one_replace_string_seven_replace_string_
one---------seven*********
one56 12seven345 789

subn()

使用字符串或函数返回的字符串替换pattern对象匹配到的字符串,返回一个元组(替换后的字符串, 替换的次数),等同于re.subn()函数。

import re

pattern = re.compile(r'(\w+) (\w+)')
word = 'hello 123, hello 456'

def func(word):
    return 'hi' + ' ' + word.group(1)  # 返回一个字符串用于替换

print(pattern.subn(r'hello world', word))  # 使用字符串替换
print(pattern.subn(r'\2 \1', word))  # 引用匹配到的子串的分组进行替换
print(pattern.subn(func, word))  # 使用函数返回一个字符串用于替换
print(pattern.subn(func, word, 1))   # 指定替换的次数
# 结果
('hello world, hello world', 2)
('123 hello, 456 hello', 2)
('hi hello, hi hello', 2)
('hi hello, hello 456', 1)

从上面可以看出re模块有两种使用方式:

  • 将正则表达放入re模块的各函数执行
  • 使用compile函数预编译正则表达式产生pattern对象,使用pattern对象的各个方法

如何选择使用方式呢?如果一个正则表达式需要使用多次,出于效率的考虑,可预编译正则表达式,即第二种方式。

3. 匹配中文

中文的 unicode 编码范围 主要在 [\u4e00-\u9fa5],这里说主要是因为这个范围并不完整,比如没有包括全角(中文)标点,不过,在大部分情况下,应该是够用的。

import re

word = '你好,hello,世界'

result = re.findall(r'[\u4e00-\u9fa5]+', word)
print(result)
# 结果
['你好', '世界']

4. 贪婪匹配

python中,正则表达式默认为贪婪匹配,即匹配尽可能多的字符。

import re

word = 'aa<div>test1</div>bb<div>test2</div>cc'

result = re.findall(r'<div>.+</div>', word)
print(result)

result = re.findall(r'<div>.+?</div>', word)
print(result)
# 结果
['<div>test1</div>bb<div>test2</div>']
['<div>test1</div>', '<div>test2</div>']

由于是贪婪匹配,在成功匹配第一个</div>后,会继续向右尝试匹配,查看是否还有更长的可以成功匹配的子串。若想非贪婪匹配,可在+后面添加一个?。

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

推荐阅读更多精彩内容

  • re模块手册 本模块提供了和Perl里的正则表达式类似的功能,不关是正则表达式本身还是被搜索的字符串,都可以...
    喜欢吃栗子阅读 3,981评论 0 13
  • 搞懂Python 正则表达式用法 Python 正则表达式 正则表达式是一个特殊的字符序列,它能帮助你方便的检查一...
    厦热阅读 1,568评论 0 2
  • #首先,python中的正则表达式大致分为以下几部分: 元字符 模式 函数 re 内置对象用法 分组用法 环视用法...
    mapuboy阅读 1,599评论 0 51
  • 前言 字符串是编程中非常常用的数据结构,对它的操作处理也非常重要。所以学透本知识点,对以后开发过程中对字符串处理,...
    TensorFlow开发者阅读 776评论 0 4
  • 桂千,女性,淡水鱼,是专出美女的桂花鱼族。桂千从小就认定自己与众不同,她在很多事物上的理解不同于其他鱼,总有自己的...
    陈铨阅读 282评论 0 0