引言
正则表达式,又称规则表达式,英语称为 Regular Expression,通常被用来检索、替换那些符合某个模式(规则)的文本,例如在以上任务中匹配身份证号或者电话号码,是在文本预处理过程中常用的技术。
语法
基本的正则表达式的语法:
.
: 能够匹配除换行符 \n 以外的任意单个字符。\w
:与单个字母数字字符匹配。\W
:与单个非字母数字字符匹配。\d
:与单个数字匹配。\D
:与单个非数字匹配。\s
:与单个空格字符(空格,换行符,返回符,制表符,表格)匹配。\S
:与任何非空格字符匹配。\t
:匹配单个 tab 符。\n
:匹配单个换行符。\r
:匹配单个回车符。^
和$
:分别匹配字符串的开头或结尾。[..]
:匹配方括号中…表达的字符。[^..]
:匹配方括号中…表达以外的任何字符。{m,n}
:匹配前一个字符的出现次数在 m 至 n 次之间。a|b
:匹配 a 或 b。?
:匹配前一个字符出现次数 0 或 1。+
:模式前一个字符出现 1 次或多次。*
:模式前一个字符出现 0 次或多次。\
:转义字符,通常用于将一些被占用成为正则表达的符号还原为原来的意思,比如 \+ 表示加号。()
:被括起来的表达式部分将作为分组,并返回相匹配的文本。
语法规则可能略多,但是在 Python 中,通过内嵌集成 re 模块可以直接调用从而快速实现正则匹配,re 中常用的功能有:
re.match()
:从字符串中的首字符开始匹配相应的模式串。re.search()
:从字符串中的任意位置都可以匹配相应的模式串,只要找到第一个匹配即返回,如果字符串没有匹配,则返回 None 。re.findall()
:从字符串中的任意位置都可以匹配相应的模式串,找到所有匹配情况后返回,如果字符串没有匹配,则返回 None 。re.sub()
:从字符串中的任意位置都可以匹配相应的模式串,找到所有匹配情况后替换成希望的表达形式,返回替换后的字符串。
代码
接下来分别就 re.match()
,re.search()
,re.findall()
做一些简单的示例:
import re
# r'自然语言'指模式串,'自然语言处理'指要被匹配的字符串
# 注:模式串前加 r 是为了防止字符转义
result = re.match(r'自然语言', '自然语言处理')
print(result) # 匹配成功返回一个匹配的对象,否则返回None
# 输出结果
# <re.Match object; span=(0, 4), match='自然语言'>
调用其他函数获取更多信息:
print('Matching string :', result.group()) # 获取被匹配到的部分
print('Starting position of the match :', result.start()) # 获取被匹配到的部分初始位置
print('Ending position of the match :', result.end()) # 获取被匹配到的部分结束位置
# 输出结果
# Matching string : 自然语言
# Starting position of the match : 0
# Ending position of the match : 4
如果匹配失败:
result = re.match(r'语言', '自然语言处理') # 注意 match 需要从首字符开始匹配
print(result) # 匹配成功返回一个匹配的对象,否则返回 None
# 输出结果
# None
第二种匹配方式:
# 搜寻字符串中任意位置都可能匹配的模式串,找到首个即返回
result = re.search(r'语言', '自然语言处理自然语言')
print(result) # 匹配成功返回一个匹配的对象,否则返回 None
print('Matching string :', result.group()) # 获取被匹配到的部分
# 输出结果
# <re.Match object; span=(2, 4), match='语言'>
# Matching string : 语言
第三种匹配方式:
# 搜寻字符串中任意位置都可能匹配的模式串,遍历匹配,可以获取字符串中所有匹配的字符串,
result = re.findall(r'语言', '自然语言处理自然语言')
print(result) # 返回一个列表
# 输出结果
# ['语言', '语言']
在这里总结一下 re.match()
, re.search()
以及 re.findall()
之间的区别:
re.match()
只从字符串的开始位置进行匹配,如果字符串不符合正则表达式,则匹配失败,函数返回 None ;re.search()
匹配整个字符串,从任意位置都可以开始匹配,直到找到一个匹配即返回 ;re.findall()
则会找到所有匹配结果并返回。
如果想替换字符串中的符合某些模式的地方,可以使用 re.sub()
:
# r'自然语言'指模式串,'language'指替换内容,'自然语言处理'指要被匹配的字符串
result = re.sub(r'语言', 'language', '自然语言处理')
print(result)
# 输出结果
# 自然language处理
实例
抽取一段英文中的首个单词。
# 使用了模式串 r'^\w+',这是因为 ^ 表示字符串的开始部分,而 \w+ 可以表示多个连续的字母。
result = re.findall(r'^\w+', 'Whatever is worth doing is worth doing well.')
print(result)
# 输出结果
# ['Whatever']
返回邮箱地址中的域名。
# r'@\w+\.(\w+)' 中最后的 \w+ 左右加了括号,因此只会返回括号中匹配的部分
# . 能够匹配除换行符 \n 以外的任意单个字符,这里需要匹配原本的 . 所以加上转义字符变为 \.
result = re.findall(
r'@\w+\.(\w+)', 'abc.test@gmail.com, xyz@test.in, test.first@analyticsvidhya.com, first.test@rest.biz')
print(result)
# 输出结果
# ['com', 'in', 'com', 'biz']
返回字符串中固定格式的日期,如 08-05-2021。
# \d{2}表示两个数字,同理得表达式为 r'\d{2}-\d{2}-\d{4}'
result = re.findall(
r'\d{2}-\d{2}-\d{4}', 'Amit 34-3456 12-05-2007, XYZ 56-4532 11-11-2011, ABC 67-8945 12-01-2009')
print(result)
# 输出结果
# ['12-05-2007', '11-11-2011', '12-01-2009']
只保留字符串中的中文字符。
# 中文的Unicode范围为 \u4e00-\u9fa5,前面加 ^ 表示非汉字
# 注意 ^ 放在[]中才表示“非”的意义,而放在外面则表示“初始位置”的意义
result = re.sub(r'[^\u4e00-\u9fa5]', '', 'language自然!!·~语言##处理;’;')
print(result)
# 输出结果
# 自然语言处理
验证是否为身份证号码。
注:身份证号可能为 15 或 18 位,15 位全为数字,18 位中前 17 位为数字,最后一位为 X 或者 x。
# r'(^\d{15}$)|(^\d{18}$)|(^\d{17}(X|x)$)' 中三个大括号中的表达式分别对应以上三种情况
# 一头一尾的 ^ 以及 $ 表明匹配的范围是字符串的起止范围
result = re.match(
r'(^\d{15}$)|(^\d{18}$)|(^\d{17}(X|x)$)', '94023856739300998X')
print(result)
# 输出结果
# <re.Match object; span=(0, 18), match='94023856739300998X'>