[Python] 常用模块(2):内建模块 -- re 以及正则表达式

本文深入解析Python正则表达式的使用技巧,包括模糊规则、字符匹配、重复匹配及贪婪搜索等内容,同时介绍了re模块的功能,如compile、findall、search等方法,帮助读者掌握高效的数据抓取和字符串处理能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Python 常用模块系列:

  • [Python] 常用模块(1):内建模块 – random & datetime
  • [Python] 常用模块(2):内建模块 – re 以及正则表达式(本文)
  • [Python] 常用模块(3):内建模块 – math & itertools
  • [Python] 常用模块(4):NumPy 上
  • [Python] 常用模块(4):NumPy 中
  • [Python] 常用模块(4):NumPy 下
  • [Python] 常用模块(5):pandas 1
  • [Python] 常用模块(5):pandas 2
  • [Python] 常用模块(5):pandas 3
  • [Python] 常用模块(5):pandas 4
  • [Python] 常用模块(5):pandas 5
  • [Python] 常用模块(5):pandas 6
  • [Python] 常用模块(5):pandas 7
  • [Python] 常用模块(5):pandas 8
  • [Python] 常用模块(5):pandas 9

正则表达式的介绍

正则表达式在抓取信息上有着非常重要的作用,因为正则表达式可以识别特定格式的字符串,比如电话号码、电子邮箱地址等等。而且网页语言是高度格式化的,因此正则表达式在网页爬虫上的作用也非常大。和字符串格式化类似,正则表达式可以在字符串前加 r 来让 python 识别:

r"avengers"

这样可以在所有文本中识别 avengers 这个词。

正则表达式的模糊规则

虽然正则表达式可以用来识别特定字符串,更多时候我们希望用正则表达式识别一个字符串格式,比如所有手机号码。正则表达式提供了相应的语法进行指定格式的字符串抓取。

字符的“或”匹配

有时候我们希望匹配多个字符、字符串中的任意一个,这时可以将希望匹配的字符放进 [] 里:

r"m[ae]n"

这个正则表达式的意思是匹配 manmen[] 内还可以填充一个范围,比如 [0-9a-zA-Z] 匹配了所有数字、小写字母和大写字母中的任一个,这个范围可以任意指定,比如 [0-5] 匹配 012345 中的任一个数字。

“或”匹配也可以使用系统保留字符 |,比如 "man|men""m[ae]n" 的效果是一样的。|认为分割线两边的字符串都是二选一的,所以可以选择字符串,比如 "Tony|Steve" 是选择 Tony 或 Steve 中的一个。如果引号中有其他字符串,为避免歧义,需要将或匹配的字符串用 () 括起来,例如

r"(Tony|Steve) Natasha"

就是选择了 TonySteve 中的一个和 Natasha;如果没有 () 则选择了 TonySteve Natasha 中的一个。

保留字符和脱离

很多字符有特殊的含义,它们被系统使用。这样的字符有:

字符含义
.匹配任何字符(除了 /n
^匹配“开头”
$匹配“结尾”
?匹配一个字符串就结束

. 可以匹配除了换行符(/n)以外的任意字符;^$表示正则表达式的匹配必须在字符串的开头或结尾。? 的作用下面再说。

这样问题就来了,如果想匹配这些字符本身怎么办?办法是在这些保留字符前加 \,这样系统就明白了你想匹配这些字符本身。这个 \ 本身也是系统保留字符,意味着想匹配它本身,需要写成 \\

还有一点要注意,在 [] 里的 ^ 假如在字符串的开头,它的含义变成了“除了 xxx 以外的字符串”,比如[^1] 的含义是“除了 1 以外的所有字符。

重复匹配

因为中国大陆的手机号码加上国家区号一共 11 位,假如我们想匹配,难道我们要写 10 遍[0-9](号码第一位肯定是 1,所以是 10 个模糊字符)?当然不需要,因为正则表达式提供了字符的重复匹配方法:

字符含义
*重复零次或多次
+重复一次或多次
{n, m}重复 n 至 m 次
{n}重复 n 次

也可以省略 {n, m} 中的任何一边,比如 {n,} 代表至少重复 n 次,而 {, m} 代表之多重复 m 次。

贪婪搜索和 ‘?’

正则表达式的搜索都是“贪婪”的,意味着假如你使用了不限匹配次数的 *+,系统会搜索整个文本试图找到所有的匹配。终结这种贪婪搜索的方法是在正则表达式后面加上 ?,这样系统在搜索到第一个匹配以后就会停止搜索。

类型匹配

系统已经定义好了若干系统保留字符串,用来匹配指定字符类型:

字符含义
\d任意数字
\D不是数字的任意字符
\s任意 whitespace([空格\t\n]等)
\S不是 whitespace 的任意字符
\w任意大小写字母,数字和空格
\W不属于 \w 的任意字符

这里要说明一点,whitespace 指的是空白占位符,比如空格、tab(\t)、换行符(\n)等等。

re 模块

正则表达式的语法大概说完了,下面咱们看 re 模块。

载入模块

因为我们要用到 re 模块中的多数功能,所以我们载入整个模块:

import re

以后除非是载入模块中的某个函数,默认已经载入整个模块了。

re.compile(pattern, flags = 0)

将一个正则表达式的样式编译为一个正则对象用于匹配。如果这个正则对象会经常用到,预编译会节省很多打字的时间。正则对象下面会用到。

  • 多行匹配
    默认情况下,正则表达式把整个文本看成一个整体,比如:
"""
Tony said,
'I'm Iron Man!'
"""

会被系统看成

"Tony said,\n'I'm Iron Man!'"

这样假如我们希望用 r"^I\'m" 匹配行首的 I'm,系统会返回 None,因为系统把整个文本看成一行,认为行首是 Tony。这时我们使用 flags = re.M 参数,让系统将换行符识别出来。

  • 匹配时忽略大小写
    有时候我们希望寻找匹配的时候忽略大小写,可以使用 flag = re.I
re.findall(pattern, string, flags = 0)

搜索 string 内所有符合 pattern 的字符串,返回一个列表。

>>> re.findall(r"I\S+", "I'm Iron Man!")
["I'm", 'Iron']
re.finditer(pattern, string, flags = 0)

返回一个迭代器,这个迭代器 yield 匹配字符串。

>>> match = re.finditer(r"I\S+", "I'm Iron Man!")
>>> next(match)
<re.Match object; span=(0, 3), match="I'm">
>>> next(match)
<re.Match object; span=(4, 8), match='Iron'>
>>> next(match)
re.search(pattern, string, flags = 0)

返回第一个匹配的字符串。

>>> re.search(r"I\S+", "I'm Iron Man!")
<re.Match object; span=(0, 3), match="I'm">
re.sub(pattern, repl, string, count = 0)

搜索 string 里符合 pattern 的字符串,以 repl 代替最多替换几次(count 参数)。

>>> re.sub(r"I\S+", "He is", "I'm Iron Man!", count = 1)
He is Iron Man!
re.split(pattern, string, maxsplit = 0, flags = 0)

用 pattern 分开 string。 如果在 pattern 中捕获到括号,那么所有的组里的文字也会包含在列表里。如果 maxsplit 非零, 最多进行 maxsplit 次分隔, 剩下的字符全部返回到列表的最后一个元素。

>>> re.split(r"\s", "I'm Iron Man!")
["I'm", 'Iron', 'Man!']

正则对象的方法

正则对象的方法与 re 函数非常相似,无非就是把参数里的 pattern 变成了方法的对象。比如:

>>> ptn = re.compile("I\S+")
>>> ptn.findall("I'm Iron Man!")
["I'm", 'Iron']
匹配分组

通过对正则表达式用 (),我们可以为匹配分组,可以轻松定位所找到的内容。

>>> match = re.search(r"(I'm) (Iron) Man!", "I'm Iron Man!")
>>> match.groups()
("I'm", 'Iron')
>>> match.group(1)
"I'm"
>>> match.group(2)
'Iron'

如果分组太多,数字定位可以会不方便,这时我们可以在括号的开头写 ?P<名字> 给这个组定义一个名字,之后可以用这个名字找到组的内容。

>>> match = re.search(r"(?P<name>I'm) (?P<role>Iron) Man!", "I'm Iron Man!")
>>> match.group("name")
"I'm"
>>> match.group("role")
'Iron'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值