正则表达式(Regular Expression,通常简写为regex或regexp)是一种强大的文本处理工具,它使用一种特定的模式来描述和匹配字符串。正则表达式可以用于搜索、替换和验证文本中的特定字符序列
。
简单来说,可以理解为正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配
。
一、基本概念和常见元素
1、基本元素
- 字符类:
匹配方括号中的任意字符
。例如,[abc] 匹配 "a"、"b" 或 "c"。 - 范围:使用
连字符 -
来表示字符范围。例如,[a-z] 匹配任何小写字母。 - 否定字符类:在字符类前加上
^ 符号
可以匹配不在该字符类中的任意字符。例如,[^a-z] 匹配任何非小写字母的字符。 - 元字符:具有特殊含义的字符,如
.
(匹配任意字符,除了换行符)、*
(匹配前面的元素零次或多次)、+
(匹配前面的元素一次或多次)、?
(匹配前面的元素零次或一次)等。 - 锚点:用于指定匹配的位置,如
^
(匹配字符串的开头)和$
(匹配字符串的结尾)。
2、分组和引用
- 圆括号:用于分组,并
捕获匹配的子字符串
。 - 反向引用:使用
\1、\2
等来引用之前捕获的分组。
3、修饰符和标志
- 多行模式:使 ^ 和 $ 分别匹配每一行的开头和结尾,而不是整个字符串的开头和结尾。
- 忽略大小写:使匹配时不区分大小写。
- 全局搜索:搜索整个字符串中的所有匹配项,而不是只找到第一个就停止。
4、常见应用
- 验证:检查字符串是否符合特定的格式或规则,如电子邮件地址、电话号码等。
- 搜索和替换:在文本中查找特定的模式,并用其他文本替换它。
- 分割字符串:使用正则表达式作为分隔符来分割字符串。
示例:
python
import re
text = "There are 123 apples and 456 oranges."
pattern = r'\d+' # 匹配一个或多个数字
matches = re.findall(pattern, text)
print(matches) # 输出: ['123', '456']
示例中, r'\d+'
是一个正则表达式,其中 \d
匹配任意数字, +
匹配前面的元素(即数字)一次或多次。re.findall() 函数
用于在文本中查找所有匹配该正则表达式的子字符串。
二、python 正则表达式 re模块
re 模块使 Python 语言拥有全部的正则表达式功能。这个模块提供了一系列函数和方法,用于匹配和操作字符串。接下来将学习re模块的处理函数。
1、re模块的基本函数
python
>>> import re
>>> dir(re)
['A', 'ASCII', 'DEBUG', 'DOTALL', 'I', 'IGNORECASE', 'L', 'LOCALE', 'M', 'MULTILINE',
'Match', 'NOFLAG', 'Pattern', 'RegexFlag', 'S', 'Scanner', 'T', 'TEMPLATE', 'U',
'UNICODE', 'VERBOSE', 'X', '_MAXCACHE', '_MAXCACHE2', '__all__', '__builtins__',
'__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__',
'__path__', '__spec__', '__version__', '_cache', '_cache2', '_casefix',
'_compile', '_compile_template', '_compiler', '_constants', '_parser',
'_pickle', '_special_chars_map', '_sre', 'compile', 'copyreg', 'enum',
'error', 'escape', 'findall', 'finditer', 'fullmatch', 'functools',
'match', 'purge', 'search', 'split', 'sub', 'subn', 'template']
>>>
和其他模块一样,在使用re模块来处理正则表达式时,要先导入 re 模块
python
import re
2、re模块函数使用
正则表达式的语法和功能非常强大和灵活,可以通过学习更多的元字符、量词、边界匹配来扩展正则表达式的知识。
(1)re.match()
从字符串的起始位置匹配一个模式
,如果匹配成功,返回一个匹配对象;否则返回None
语法:
python
re.match(pattern, string, flags=0)
参数说明--
pattern:匹配的正则表达式
string :要匹配的字符串。
flags :标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。参见:正则表达式修饰符 - 可选标志
匹配对象方法:可使用 group(num)
或 groups()
匹配对象函数来获取匹配表达式。
- group(num=0) 匹配的整个表达式的字符串,group()可一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。
- groups() 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
示例如下:
python
import re
line = "Cats are smarter than dogs"
matchObj = re.match(r'(.*) are (.*?) than (.*)', line)
if matchObj:
print("matchObj.group() : ", matchObj.group()) #输出 Cats are smarter than dogs
print("matchObj.groups() : ", matchObj.groups()) #输出 ('Cats', 'smarter', 'dogs')
print("matchObj.group(1) : ", matchObj.group(1)) #输出 Cats
print("matchObj.group(2) : ", matchObj.group(2)) #输出 smarter
print("matchObj.group(3) : ", matchObj.group(3)) #输出dogs
else:
print("No match!!")
以上示例,正则表达式:r'(.*) are (.*?) than (.*)'
其中 (.*)
:匹配任意数量的任意字符(除了换行符),并将它们捕获到第一个组中。
(.*?)
:匹配任意数量的任意字符(除了换行符),但尽可能少地匹配(非贪婪模式),并将它们捕获到第二个组中。
(2)re.search()
扫描整个字符串,返回第一个成功匹配的对象。
语法:
python
re.search(pattern, string, flags=0)
- re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None。
- re.search匹配整个字符串,直到找到一个匹配。
python
import re
print(re.match('hello', 'hello.python.com').span()) # 在起始位置匹配 输出:(0, 5)
print(re.match('com', 'hello.python.com')) # 不在起始位置匹配 输出:None
print(re.search('hello', 'hello.python.com').span()) # 在起始位置匹配 输出:(0, 5)
print(re.search('com', 'hello.python.com').span()) # 不在起始位置匹配 输出:(13, 16)
(3)re.findall()
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果有多个匹配模式,则返回元组列表,如果没有找到匹配的,则返回空列表。
注意: match 和 search 是匹配一次 findall 匹配所有。
语法:
python
findall(string, pos, endpos])
参数说明:
string : 待匹配的字符串。
pos : 可选参数,指定字符串的起始位置,默认为 0。
endpos : 可选参数,指定字符串的结束位置,默认为字符串的长度。
示例:
python
import re
pattern = re.compile(r'\d+') # 匹配一个或多个数字
text= "I have 100 leomon trees and 20 rivers"
findall= pattern.findall(text)
findall1= pattern.findall(text,0,10)
print("findall:",findall) #输出:findall: ['100', '20']
print("findall1:",findall1) #输出:findall1: ['100']
(4)re.finditer()
找到字符串中所有匹配的部分,并返回一个迭代器,产生匹配对象。
语法:
python
re.finditer(pattern, string, flags=0)
示例:
python
import re
pattern = re.compile(r'\d+') # 匹配一个或多个数字
text= "I have 100 leomon trees and 20 rivers"
findall= pattern.finditer(text)
findall1= pattern.finditer(text,0,10)
for match in findall:
print (match.group() )
for match in findall1:
print (match.group() )
运行结果:
python
100
20
100
(5)re.sub():检索和替换
在字符串中查找匹配正则表达式的部分,并用另一个字符串替换它们。
语法:
python
re.sub(pattern, repl, string, count=0, flags=0)
参数说明:
pattern : 正则中的模式字符串。
repl : 替换的字符串,也可为一个函数。
string : 要被查找替换的原始字符串。
count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
(6)re.split():分割
split 方法按照能够匹配的子串将字符串分割后返回列表.
语法:
python
re.split(pattern, string, maxsplit=0, flags=0])
参数说明:
- pattern, string同上。
- maxsplit 分隔次数,maxsplit=1 分隔一次,默认为
0,不限制次数。 - flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。参见:正则表达式修饰符 - 可选标志
(7)re.compile():
编译正则表达式,根据一个模式字符串和可选的标志参数生成一个正则表达式( Pattern )对象。
即:预编译一个正则表达式对象,然后重复使用它。
该对象拥有一系列方法用于正则表达式匹配、搜索、替换等操作。
语法:
python
re.compile(pattern, flags=0)
① pattern : 一个字符串形式的正则表达式
② flags : 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:
- 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 为了增加可读性,忽略空格和 # 后面的注释
编译后的Pattern对象可以使用的方法包括match()、search()、findall()、finditer()、sub()、split()等
示例:
python
import re
# 编译一个正则表达式
pattern = re.compile(r'\d+') # 匹配一个或多个数字
# 使用编译后的正则表达式对象进行匹配
text = "123 apples and 456 oranges."
# 使用match方法从字符串的起始位置匹配
match = pattern.match(text)
if match:
print("Match at start:", match.group()) #输出 Match at start: 123
else:
print("No match at start.")
# 使用search方法在整个字符串中搜索匹配项
search = pattern.search(text)
if search:
print("Match found:", search.group()) # 输出: Match found: 123
else:
print("No match found.")
# 使用findall方法找到所有匹配项
matches = pattern.findall(text)
print("All matches:", matches) # 输出: All matches: ['123', '456']
compile()函数的好处:可将正则表达式的编译和匹配操作分开,多次重用编译后的正则表达式对象,提高性能。使代码更清晰、更易于维护。
(8)修饰符和标志
在编译正则表达式时,可以使用一些标志来改变匹配的行为。例如,re.IGNORECASE或re.I用于忽略大小写匹配。
示例如下:
python
import re
print("----re.match()匹配----")
pattern = r'\d+' #匹配一个或多个数字
text = "123 apples and 456 oranges"
match = re.match(pattern, text)
if match:
print("Found:", match.group()) # 输出: Found: 123
print("----re.search()扫描----")
match = re.search(pattern, text)
if match:
print("Found:", match.group()) # 输出: Found: 123
print("----re.findall()函数----")#找到字符串中所有匹配的部分,并返回一个列表
matches = re.findall(pattern, text)
print(matches) # 输出: ['123', '456']
print("----re.finditer()函数----")
#找到字符串中所有匹配的部分,并返回一个迭代器,产生匹配对象。
matches = re.finditer(pattern, text)
for match in matches:
print(match.group()) # 分别输出: 123 和 456
print("----re.sub()替换----")
new_text = re.sub(r'\d+', 'XXX', text)
print(new_text) # 输出: XXX apples and XXX oranges
print("----re.split()分割----")
words = re.split(r'\d+', text)
print(words) # 输出: ['', ' apples and ', ' oranges']
print("----re.compile()预编译----")
compiled_pattern = re.compile(r'\d+')
matches = compiled_pattern.findall(text)
print(matches) # 输出: ['123', '456']
print("----re.IGNORECASE或re.I用于忽略大小写匹配----") #修饰符和标志
pattern = re.compile(r'apple', re.IGNORECASE)
match = pattern.search('There is an Apple on the table.')
if match:
print("Found:", match.group()) # 输出: Found: Apple
三、应用
'(?P...)' 分组匹配
示例1:日期"The date is 2024-04-18."
python
import re
# 定义一个包含日期的字符串
date_string = "The date is 2023-03-15."
# 使用命名分组来匹配日期
pattern = r"The date is (?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})."
# 执行匹配
match = re.search(pattern, date_string)
# 如果匹配成功,打印命名分组的值
if match:
print("match.group:", match.group())
print("group-Year:", match.group("year"))
print("group-Month:", match.group("month"))
print("group-Day:", match.group("day"))
print("match.groups:", match.groups())
print("groups-Year:", match.groups("year"))
print("groups-Month:", match.groups("month"))
print("groups-Day:", match.groups("day"))
print("match.groupdict:", match.groupdict())
else:
print("No match found.")
运行结果:
python
match.group: The date is 2023-03-15.
group-Year: 2023
group-Month: 03
group-Day: 15
match.groups: ('2023', '03', '15')
groups-Year: ('2023', '03', '15')
groups-Month: ('2023', '03', '15')
groups-Day: ('2023', '03', '15')
match.groupdict: {'year': '2023', 'month': '03', 'day': '15'}
示例2:识别身份证ID
在Python的re模块中,当使用命名分组(即(?P...)语法)进行正则表达式匹配时,匹配对象会提供一个名为groupdict()的方法。这个方法返回一个字典,其中的键是命名分组的名称,值是相应分组匹配到的字符串。这对于提取和访问匹配到的命名分组非常有用。
python
import re
id = '4102211990xxxxxxxx'
res = re.search(r'(?P<province>\d{3})(?P<city>\d{3})(?P<born_year>\d{4})', id[:10])
if res:
print(res.groupdict())#输出{'province': '410', 'city': '221', 'born_year': '1990'}
else:
print("No match found.")
or
python
import re
id = '4102211990xxxxxxxx'
res = re.search(r'(?P<province>\d{3})(?P<city>\d{3})(?P<born_year>\d{4})',id)
print(res.groupdict())