主页
avatar

Kared

【全面指南】正则表达式:文本处理的瑞士军刀

在数据世界里,文本数据无所不在,处理它们是日常工作的一部分。数据清洗、日志分析或是文本挖掘,都需要一种既强大又灵活的工具。而正则表达式,一种用精巧的符号序列构建的技术,就像是程序员的瑞士军刀,简约而不简单,赋予文本处理以惊人的力量。本博客将带你深入正则表达式的世界,展示它如何简化复杂的文本任务。

正则表达式并不是 Python 独有的工具,它同样适用于其他编程语言。然而,Python 通过 re 库提供了对正则表达式的完整支持。利用这个强大的库,我们可以在 Python 环境中灵活地运用正则表达式。在 Python 中,几乎所有正则表达式的操作都依赖于 re 库。下面,我们将列出一些常用的匹配规则,并探讨 re 库中的一些常用方法。

1、正则表达式模式

以下表格总结了一些基本的正则表达式模式及其描述:

模式描述
\w匹配字母、数字及下划线
\W匹配非字母、数字及下划线的字符
\s匹配任意空白字符,等价于[\t\n\r\f]
\S匹配任意非空白字符
\d匹配任意数字,等价于[0-9]
\D匹配非数字字符
\A匹配字符串开头
\Z匹配字符串结尾(不包括换行符)
\z匹配字符串结尾(包括换行符)
\G匹配最后一次匹配结束的位置
\n匹配换行符
\t匹配制表符
^匹配一行的开头
$匹配一行的结尾
.匹配任意字符(默认不包括换行符),使用re.DOTALL 标记后,可匹配包括换行符的任意字符
[...]匹配方括号内的任一字符,例如[amk] 匹配 amk
[^...]匹配不在方括号内的任一字符,例如[^abc] 匹配除 abc 之外的任意字符
*匹配0次或多次前面的表达式
+匹配1次或多次前面的表达式
?匹配0次或1次前面的表达式,采用非贪婪方式
{n}精确匹配n 次前面的表达式
{n, m}匹配nm 次前面的表达式,采用贪婪方式
a|b匹配ab
()将括号内的表达式作为一个分组

2、正则表达式修饰符(可选标志)

修饰符可以改变正则表达式的匹配行为。以下是一些常用的正则表达式修饰符及其作用:

修饰符描述
re.I使匹配对大小写不敏感,即忽略大小写
re.L使\w\W\b\B\s\S 这些特殊字符集依赖于当前环境
re.M多行匹配,影响^$ 的行为
re.S使. 匹配包括换行在内的所有字符
re.U使\w\W\b\B\d\D\s\S 依赖于 Unicode 字符属性数据库
re.X提高可读性,允许在正则表达式中添加空格和注释(# 后面的内容)

3、正则表达式实例

① 字符匹配

这是最基础的匹配方式,直接通过字面值进行匹配。

实例描述
python匹配字符串 “python”

② 字符类

字符类允许你匹配指定的字符集合。通过使用方括号,可以指定一个字符集,从而匹配多种可能的字符。

实例描述
[Pp]ython匹配 “Python” 或 “python”
pytho[ne]匹配 “python” 或 “pythoe”
[aeiou]匹配任一元音字母
[0-9]匹配任一数字,等同于[0123456789]
[a-z]匹配任一小写字母
[A-Z]匹配任一大写字母
[a-zA-Z0-9]匹配任一字母或数字
[^aeiou]匹配除 “aeiou” 以外的任意字符
[^0-9]匹配任意非数字字符

③ 特殊字符类

特殊字符类用于匹配特定类型的字符,如数字、空白等,而无需显式地列出所有可能的字符。

实例描述
.匹配除\n 之外的任何单个字符。要匹配包括 \n 在内的任何字符,请使用 [.\n] 模式。
\d匹配一个数字字符,等价于[0-9]
\D匹配一个非数字字符,等价于[^0-9]
\s匹配任何空白字符,等价于[ \f\n\r\t\v]
\S匹配任何非空白字符,等价于[^ \f\n\r\t\v]
\w匹配包括下划线的任何单词字符,等价于[A-Za-z0-9_]
\W匹配任何非单词字符,等价于[^A-Za-z0-9_]

4、正则表达式方法

re.match() 函数

re.match() 函数尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match() 就返回 None

re.match(pattern, string, flags=0)

参数说明:

  • pattern: 要匹配的正则表达式。
  • string: 要匹配的字符串。
  • flags: 标志位,用于控制正则表达式的匹配方式。

匹配成功,re.match 方法返回一个匹配的对象;否则返回 None,我们可以使用 group(num)groups() 方法从匹配对象中获取信息。

re.search() 函数

re.search() 函数扫描整个字符串并返回第一个成功的匹配。

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

re.match 类似,re.search 在匹配成功时返回一个匹配对象,否则返回 None

re.match()re.search() 的区别

re.match() 只匹配字符串的开始部分,如果开头不符合正则表达式,则匹配失败,函数返回 None;而 re.search() 匹配整个字符串,直到找到一个匹配项。

import re
 
string = "This is Pluto's personal blog"
 
match = re.match(r'blog', string, re.M|re.I)
if match:
   print("match.group() : ", match.group())
else:
   print("No match!!")
 
search = re.search(r'blog', string, re.M|re.I)
if search:
   print("search.group() : ", search.group())
else:
   print("No search!!")

输出结果将显示 “No match!!” 和 “search.group() : blog”,因为 match() 没有在字符串开头找到 “blog”,而 search() 在整个字符串中进行了搜索。

re.sub() 函数

re.sub() 函数用于替换字符串中的匹配项。

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

参数说明:

  • pattern: 匹配的正则表达式。
  • repl: 替换的字符串或一个函数。
  • string: 要匹配的字符串。
  • count: 模式匹配后替换的最大次数,默认为 0,意味着替换所有的匹配。

re.compile() 函数

re.compile() 函数用于编译正则表达式,生成一个正则表达式对象(Pattern 对象),供 match()search() 等函数使用。

re.compile(pattern, flags=0)

通过预编译可以提高正则表达式的重用性,并提升匹配效率。

findall()finditer() 函数

findall() 在字符串中找到正则表达式所匹配的所有子串,并返回一个列表;finditer() 返回一个迭代器,其中每个元素都是 MatchObject 实例。

re.split() 函数

re.split() 函数按照正则表达式匹配的子串将字符串分割后返回列表。

5、正则表达式对象

在 Python 的 re 模块中,正则表达式的编译和匹配操作都与特定的对象相关联。这些对象增强了正则表达式的功能,使得文本处理更加高效和灵活。下面是两个最核心的对象:

re.RegexObject 对象

re.RegexObject 是由 re.compile() 方法返回的对象,它代表了一个编译后的正则表达式。这个对象预先编译了正则表达式的模式,并可被多次用于匹配操作。使用 re.RegexObject 的好处是,当你需要多次使用同一个正则表达式时,你不必在每次匹配时重新编译它,这样可以大大提高效率。

例如,如果你正在构建一个文本编辑器,需要高亮显示所有的 Python 变量名,你可以编译一个匹配 Python 变量命名规则的正则表达式,并在每次文本更新时使用它。

import re

# 编译一个匹配 Python 变量名的正则表达式
variable_regex = re.compile(r'\b[a-zA-Z_][a-zA-Z_0-9]*\b')

# 在文本中多次使用
text = "Here are some variables: var1, var2, function_name, _private_var"
matches = variable_regex.findall(text)
for match in matches:
    print("Found Python variable:", match)

re.MatchObject 对象

re.MatchObject 是由 match()search() 等匹配函数返回的对象,它包含了匹配的详细信息。这个对象提供了多种方法来获取关于匹配部分的信息,例如匹配的文本、匹配的位置等。

re.MatchObject 的常用方法包括:

  • group(): 返回匹配的字符串。
  • start(): 返回匹配开始的索引。
  • end(): 返回匹配结束的索引。
  • span(): 返回一个包含匹配 (开始, 结束) 索引的元组。

下面是一个 re.MatchObject 的使用示例:

import re

# 匹配一个简单的日期格式:YYYY-MM-DD
date_pattern = re.compile(r'(\d{4})-(\d{2})-(\d{2})')
text = "The event will take place on 2024-02-29."

match = date_pattern.search(text)
if match:
    print("Matched date:", match.group())  # 获取整个匹配的部分
    year, month, day = match.groups()      # 获取各个组的匹配部分
    print("Year:", year, "Month:", month, "Day:", day)
    print("Match starts at index:", match.start())
    print("Match ends at index:", match.end())
    print("Match span:", match.span())

通过使用这些对象和它们的方法,你可以更加精确地控制文本匹配和处理的过程,从而实现复杂的文本分析和数据提取任务。

6、常用表达式集锦

[scode type=“blue” size=“simple”]注意,正则表达式用于校验的场景非常多,而且有些表达式可能因为业务需求的不同而有所变化。上述表达式是基于常用的模式简化和优化后的结果,但在实际使用中可能需要根据具体情况进行调整。[/scode]

校验数字的表达式

  • 数字:^\d+$
  • n位的数字:^\d{n}$
  • 至少n位的数字:^\d{n,}$
  • m-n位的数字:^\d{m,n}$
  • 非零开头的数字:^[1-9]\d*$
  • 正整数:^[1-9]\d*$
  • 负整数:^-[1-9]\d*$
  • 非负整数(正整数 + 0):^\d+$
  • 非正整数(负整数 + 0):^-\d+$
  • 正浮点数:^[1-9]\d*\.\d+|0\.\d*[1-9]\d*$
  • 负浮点数:^-([1-9]\d*\.\d+|0\.\d*[1-9]\d*)$
  • 浮点数:^-?([1-9]\d*\.\d+|0\.\d*[1-9]\d*|0?\.0+|0)$

校验字符的表达式

  • 汉字:^[\u4e00-\u9fa5]+$
  • 英文和数字:^[A-Za-z0-9]+$
  • 长度为n的所有字符:^.{n}$
  • 由26个英文字母组成的字符串:^[A-Za-z]+$
  • 由26个大写英文字母组成的字符串:^[A-Z]+$
  • 由26个小写英文字母组成的字符串:^[a-z]+$
  • 由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
  • 由数字、26个英文字母或者下划线组成的字符串:^\w+$

特殊需求表达式

  • Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
  • 域名:^(?i:[a-z0-9]-?[a-z0-9]*\.)+[a-z]{2,}$
  • Internet URL:^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$
  • 手机号码(简化匹配):^\+?\d{10,13}$
  • 身份证号(简化匹配):^\d{15}(\d{2}[0-9xX])?$
  • 帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
  • 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
  • 强密码(包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
  • 日期格式(YYYY-MM-DD):^\d{4}-\d{1,2}-\d{1,2}$
  • 中国邮政编码:^[1-9]\d{5}$
  • IP地址:^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)$
Python re 正则表达式 文本处理