re模块的玩法都在这里~~~ 2

简介: re模块的玩法都在这里~~~

2. search函数

使用语法:

(1)re.search(pattern, string, flags=0)

这个函数前面已经讲解过了。

(2)Pattern对象:search(string[, pos[, endpos]])

例子:

import re
pattern = re.compile(r'd+')
m = pattern.search('one12twothree34four')
print(m.group())  # 12
print(m.groups())  # ()
m = pattern.search('one12twothree34four', 10, 30)
print(m.group())  # 34
print(m.groups())  # ()

3. findall函数

使用语法:

(1)findall(string[, pos[, endpos]])

这个函数前面已经讲解过了。

(2)Pattern对象:findall(string[, pos[, endpos]])

findall 以列表形式返回全部能匹配的子串,如果没有匹配,则返回一个空列表。

例子:

import re
pattern = re.compile(r'd+')
s1 = pattern.findall('hello world 123 456 789')
s2 = pattern.findall('one12twothree34four56', 0, 15)
print(s1)  # ['123', '456', '789']
print(s2)  # ['12', '34']

4. finditer函数

使用语法:

(1)re.finditer(pattern, string, flags=0)

这个函数前面已经讲解过了。

(2)Pattern对象:finditer(string[, pos[, endpos]])

finditer 函数与 findall 类似,但是它返回每一个匹配结果(Match 对象)的迭代器。

例子:

import re
pattern = re.compile(r'd+')
s1 = pattern.finditer('hello world 123 456 789')
s2 = pattern.finditer('one12twothree34four56', 0, 15)
for m in s1:
    print(m.group())
for m in s2:
    print(m.group())

5. split函数

使用语法:

(1)re.split(pattern, string[, maxsplit=0, flags=0])

这个函数前面已经讲解过了。

(2)Pattern对象:split(string[, maxsplit]])

maxsplit 可指定分割次数,不指定将对字符串全部分割。

例子:

import re
s = 'a,1;b 2, c'
m = re.compile(r'[s,;]+')
print(m.split(s))  # ['a', '1', 'b', '2', 'c']
m = re.compile(r'[s,;]+')
print(m.split(s, maxsplit=1))  # ['a', '1;b 2, c']

6. sub函数

使用语法:

(1)re.sub(pattern, repl, string, count=0, flags=0)

这个函数前面已经讲解过了。

(2)Pattern对象:sub(repl, string[, count])

当repl为字符串时,可以用id的形式引用分组,但不能使用编号0;当repl为函数时,返回的字符串中不能再引用分组。

例子:

import re
pattern = re.compile(r'(w+) (w+)')
s = 'ni 123, hao 456'
def func(m):
    return 'hi' + ' ' + m.group(2)
print(pattern.findall(s))  # [('ni', '123'), ('hao', '456')]
print(pattern.sub('hello world', s))  # hello world, hello world
print(pattern.sub(r' ', s))  # 123 ni, 456 hao
print(pattern.sub(func, s))  # hi 123, hi 456
print(pattern.sub(func, s, 1))  # hi 123, hao 456

7. subn函数

subn和sub类似,也用于替换操作。使用语法如下:

Pattern对象:subn(repl, string[, count])

返回一个元组,元组第一个元素和sub函数的结果相同,元组第二个元素返回替换次数。

例子:

import re
pattern = re.compile(r'(w+) (w+)')
s = 'ni 123, hao 456'
def func(m):
    return 'hi' + ' ' + m.group(2)
print(pattern.findall(s))  # [('ni', '123'), ('hao', '456')]
print(pattern.subn('hello world', s))  # ('hello world, hello world', 2)
print(pattern.subn(r' ', s))  # ('123 ni, 456 hao', 2)
print(pattern.subn(func, s))  # ('hi 123, hi 456', 2)
print(pattern.subn(func, s, 1))  # ('hi 123, hao 456', 1)

小结

1 使用Pattern对象的match、search、findall、finditer等函数可以指定匹配字符串的起始位置。

2 对re模块的两种使用方式进行对比:

  • 使用 re.compile 函数生成一个 Pattern 对象,然后使用 Pattern 对象的一系列方法对文本进行匹配查找;
  • 直接使用 re.match, re.search 和 re.findall 等函数直接对文本匹配查找。

例子:

import re
# 方法1
# 将正则表达式先编译成 Pattern 对象
pattern = re.compile(r'd+')
print(pattern.match('123, 123'))
print(pattern.search('234, 234'))
print(pattern.findall('345, 345'))
# 方法2
print(re.match(r'd+', '123, 123'))
print(re.search(r'd+', '234, 234'))
print(re.findall(r'd+', '345, 345'))

在上述例子中,我们发现他们共用了同一个正则表达式,表明上看好像没发现什么问题,但是当我们结合正则表达式的匹配过程进行分析时,就会发现这两种调用方式的效率是不一样的。


使用正则表达式进行匹配的流程是先对正则表达式进行编译,然后得到一个对象,再使用该对象对需要匹配的文本进行匹配。这时我们就发现方式2会对正则表达式进行了多次编译,这样效率不就降低了。


所以我们可以得到如下结论:


如果一个正则表达式要用多次,那么出于效率考虑,我们可以预先编译正则表达式,然后调用的一系列函数时复用。如果直接使用re.match、re.search等函数,则需要每一次都对正则表达式进行编译,效率就会降低。因此在这种情况下推荐使用第一种方式。

三、元字符和通用字符

首先,认识常用的元字符:

  • . 匹配除 “ ” 和 “ ” 之外的任何单个字符。
  • ^ 匹配字符串开始位置
  • $ 匹配字符串中结束的位置
  • * 前面的原子重复 0 次、1 次、多次,相当于{0,}
  • ? 前面的原子重复 0 次或者 1 次,相当于{0,1}
  • + 前面的原子重复 1 次或多次,相当于{1,}
  • {n} 前面的原子出现了 n 次
  • {n,} 前面的原子至少出现 n 次
  • {n,m} 前面的原子出现次数介于 n-m 之间
  • ( ) 分组,输出需要的部分

再认识常用的通用字符:

  • s 匹配空白字符
  • w 匹配任意字母/数字/下划线
  • W 和小写 w 相反,匹配任意字母/数字/下划线以外的字符
  • d 匹配十进制数字
  • D 匹配除了十进制数以外的值
  • [0-9] 匹配一个 0~9 之间的数字
  • [a-z] 匹配小写英文字母
  • [A-Z] 匹配大写英文字母

四、贪婪与非贪婪匹配

正则表达式匹配时默认的是贪婪匹配,也就是会尽可能多的匹配更多字符。如果想使用非贪婪匹配,可以在正则表达式中加上 ?。


语法


说明


重复0或1次,但尽可能少重复


重复1次或更多次,但尽可能少重复


*


重复0次或更多次,但尽可能少重复


{n,m}


重复n到m次,但尽可能少重复


{n,}


重复n或更多次,但尽可能少重复


{n}


重复n次,但尽可能少重复


例子:

import re
content = 'a<exp>hello world</exp>b<exp>ni hao</exp>c'
pattern1 = re.compile(r'<exp>.*</exp>')
s1 = pattern1.findall(content)  # 贪婪匹配 会在匹配到第一个</exp>时继续向右匹配,查找更长的匹配子串
print(s1)  # ['<exp>hello world</exp>b<exp>ni hao</exp>']
pattern2 = re.compile(r'<exp>.*?</exp>')  # 非贪婪匹配
s2 = pattern2.findall(content)
print(s2)  # ['<exp>hello world</exp>', '<exp>ni hao</exp>']

五、分组

如果你想要提取子串或是想要重复提取多个字符,那么你可以选择用定义分组的形式。用()就可以表示要提取的分组(group),接下来用几个实例来理解一下分组的使用方式:

例子1:

import re
m = re.match(r'(d{4})-(d{3,8})$', '0528-86889099')
print(m.group())  # 0528-86889099
print(m.group(1))  # 0528
print(m.group(2))  # 86889099
print(m.groups())  # ('0528', '86889099')

正则表达式 (d{4})-(d{3, 8})$ 表示匹配两个分组,第一个分组 (d{4}) 是一个有4个数字的子串,第二个分组 (d{3,8}) 表示匹配一个数字子串,子串长度为3到8之间。

例子2:

import re
s = 'ab123.456.78.90c'
m = re.search(r'(d{1,3}.){3}d{1,3}', s)
print(m.group())  # 123.456.78.90
print(m.group(1))  # 78.
print(m.groups())  # ('78.',)

正则表达式 (d{1,3}.){3}d{1,3} 的匹配过程分为两个部分,(d{1,3}.){3} 表示匹配一个长度为1到3之间的数字子串加上一个英文句号的字符串,重复匹配 3 次该字符串,d{1,3} 表示匹配一个1到3位的数字子串,所以最后得到的结果是 123.456.78.90


例子3:

import re
line = 'Cats are smarter than dogs'
match_obj = re.match(r'(.*) are (.*?) .*', line, re.M | re.I)
if match_obj:
    print(match_obj.group())  # Cats are smarter than dogs
    print(match_obj.group(1))  # Cats
    print(match_obj.group(2))  # smarter
else:
    print('no match')

(.*) 第一个分组,.* 代表匹配除换行符之外的所有字符。(.*?) 第二个匹配分组,.*? 后面加了个问号,代表非贪婪模式,只匹配符合条件的最少字符。后面的一个 .* 没有括号包围,所以不是分组,匹配效果和第一个一样,但是不计入匹配结果中。

group() 等同于group(0),表示匹配到的完整文本字符;

group(1) 得到第一组匹配结果,也就是 (.*) 匹配到的;

group(2) 得到第二组匹配结果,也就是 (.*?) 匹配到的;

因为只有匹配结果中只有两组,所以如果填 3 时会报错。

六、正则表达式修饰符

正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。多个标志可以通过 | 来指定。

修饰符


含义


re.I


忽略大小写。


re.L


做本地化识别(locale-aware)匹配。对中文支持不好。


re.M


多行匹配,影响 ^ 和 $


re.S


单行。’.’ 匹配包括换行在内的所有字符


re.U


根据Unicode字符集解析字符。这个标志影响 w, W, , B.


re.X


忽略多余空白字符,让表达式更易阅读。

import re
s = '123abCD45ABcd'
print(re.findall(r'[a-z]+', s))  # ['ab', 'cd']
print(re.findall(r'[a-z]+', s, re.I))  # ['abCD', 'ABcd']

七、扩展

[一-龥] 中文表达式的范围
>>> import re
>>> text = 'hello,马露露,五黑吗,go!'
>>> re.findall(r'[一-龥]+', text)
['马露露', '五黑吗']


相关文章
|
21天前
|
机器学习/深度学习 前端开发 Windows
【夯实技术基本功】「底层技术原理体系」全方位带你认识和透彻领悟正则表达式(Regular Expression)的开发手册(正则符号深入解析 )
【夯实技术基本功】「底层技术原理体系」全方位带你认识和透彻领悟正则表达式(Regular Expression)的开发手册(正则符号深入解析 )
36 0
|
21天前
|
存储 机器学习/深度学习 缓存
【夯实技术基本功】「底层技术原理体系」全方位带你认识和透彻领悟正则表达式(Regular Expression)的开发手册(正则表达式定义 )
【夯实技术基本功】「底层技术原理体系」全方位带你认识和透彻领悟正则表达式(Regular Expression)的开发手册(正则表达式定义 )
27 0
|
21天前
|
算法 搜索推荐 调度
Python怎么实现贪婪排名算法
Python怎么实现贪婪排名算法
27 0
|
8月前
|
Python
编程小白的自学笔记四(正则表达式模块search函数)
编程小白的自学笔记四(正则表达式模块search函数)
|
10月前
|
Python
re模块的玩法都在这里~~~ 1
re模块的玩法都在这里~~~
53 0
|
12月前
|
数据采集 自然语言处理 前端开发
再见正则表达式!这次彻底告别手写!
这篇文章的目的是让你能得到完美的正则表达式,而且还不用自己拼。 说到正则表达式,一直是令我头疼的问题,这家伙一般时候用不到,等用到的时候发现它的规则是一点儿也记不住,\d表示一个数字,\s表示包括下划线在内的任意单词字符,也就是 [A-Za-z0-9_],还有[\s\S]*可以匹配包括换行在内的任意字符串。
|
机器学习/深度学习 前端开发 JavaScript
[正则表达式]_保姆级入门教程_初入正则表达式
[正则表达式]_保姆级入门教程_初入正则表达式
89 0
|
JSON 数据格式 Python
pydantic的高阶玩法
`pydantic`是一个Python的数据验证和转换库,它的特点是轻量、快速、可扩展、可配置。笔者常用的用于数据接口schema定义与检查。 具体的基本用法本文不再做过多的介绍,可以参考[pydantic官方文档](https://docs.pydantic.dev/)。本文主要是结合实际项目开发中遇到的问题和解题思路,介绍一些`pydantic`的高阶玩法。
345 0
|
自然语言处理 测试技术 程序员
秒懂正则匹配,领略正则魅力
秒懂正则匹配,领略正则魅力
171 0
秒懂正则匹配,领略正则魅力
|
JavaScript 前端开发 索引
【重温基础】9.正则表达式
【重温基础】9.正则表达式
150 0