正则表达式(Regular Expression,简称 Regex)是一种用于匹配字符串的模式。它可以用来搜索、替换、验证文本中的特定模式。Python 中的 re 模块提供了对正则表达式的支持。
正则表达式的语法相对复杂,但理解其核心概念后,可以用非常简洁的方式来表达字符串匹配规则
符号 | 解释 |
. | 匹配任意单个字符(除换行符)。 |
^ | 匹配字符串的开头。 |
$ | 匹配字符串的结尾。 |
* | 匹配前面的字符 0 次或多次。 |
+ | 匹配前面的字符 1 次或多次。 |
? | 匹配前面的字符 0 次或 1 次。 |
{n} | 匹配前面的字符恰好 n 次 |
{n,} | 匹配前面的字符至少 n 次 |
{m,n} | 匹配前面的字符至少 m 次,至多 n 次。 |
[] | 匹配方括号中的任意一个字符(字符类)。 |
\ | 转义字符,用于匹配一些特殊字符,例如 \. 匹配句点。 |
() | 分组,标记一个子表达式。 |
| | 或运算符,匹配左边或右边的模式 |
表达式 | 说明 |
\d | 匹配任何十进制数字,等价于 [0-9] 。 |
\D | 匹配任何非数字字符。 |
\w | 匹配任何字母数字字符,等价于 [a-zA-Z0-9_] 。 |
\W | 匹配任何非字母数字字符。 |
\s | 匹配任何空白字符(空格、制表符等)。 |
\S | 匹配任何非空白字符。 |
re模块使得python拥有全部的正则表达式功能。
通过使用正则表达式,可以:
在字符串开头进行匹配,如果匹配成功则返回 Match
对象,否则返回 None
。
语法:
re.match(pattern, string, flags=0)
参数:
参数 解释 pattern 匹配的正则表达式 string 要匹配的字符串。 flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等 返回值:
匹配对象和方法 描述 group(num=0) 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。 groups() 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
import re
line = "Cats are smarter than dogs"
# .* 表示任意匹配除换行符(\n、\r)之外的任何单个或多个字符
# (.*?) 表示"非贪婪"模式,只保存第一个匹配到的子串
matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I)
if matchObj:
print ("matchObj.group() : ", matchObj.group())
print ("matchObj.group(1) : ", matchObj.group(1))
print ("matchObj.group(2) : ", matchObj.group(2))
else:
print ("No match!!")
在整个字符串中搜索,返回第一个成功匹配的 Match
对象。
语法:
re.search(pattern, string, flags=0)
参数:
参数 解释 pattern 匹配的正则表达式 string 要匹配的字符串。 flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等 返回值:
匹配对象和方法 描述 group(num=0) 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。 groups() 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
import re
result = re.search(r"world", "hello world")
if result:
print(result.group()) # Output: world
match 和 rearch 的区别:
方法 | 区别 |
re.match | 从字符串开头进行匹配,如果开始不匹配,则匹配失败 |
re.rearch | 匹配整个字符串,直到找到一个匹配 |
re.findall()
返回字符串中所有非重叠的匹配项,结果为列表。
语法:
re.findall(pattern, string, flags=0) 或 pattern.findall(string[, pos[, endpos]])
参数:
注意: match 和 search 是匹配一次 findall 匹配所有。
参数 解释 pattern 匹配的正则表达式 string 要匹配的字符串。 pos 可选参数,指定字符串的起始位置,默认为 0。 endpos 可选参数,指定字符串的结束位置,默认为字符串的长度。
import re
result = re.findall(r"\d+", "My numbers are 123 and 456")
print(result) # Output: ['123', '456']
re.finditer()
返回所有匹配项的迭代器,每个匹配项为一个 Match
对象,返回值为迭代器
语法:
re.finditer(pattern, string, flags=0)
参数:
参数 解释 pattern 匹配的正则表达式 string 要匹配的字符串。 flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等
import re
result = re.finditer(r"\d+", "My numbers are 123 and 456")
for match in result:
print(match.group()) # Output: 123, 456
re.sub()
替换匹配的字符串,可以控制替换次数。
语法:
re.sub(pattern, repl, string, count=0, flags=0)
参数:
参数 描述 pattern 正则中的模式字符串。 repl 替换的字符串,也可为一个函数。 string 要被查找替换的原始字符串。 count 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。 flags 编译时用的匹配模式,数字形式。
import re
result = re.sub(r"apple", "orange", "apple pie and apple juice")
print(result) # Output: orange pie and orange juice
repl是一个函数:
#!/usr/bin/python
import re
# 将匹配的数字乘以 2
def double(matched):
value = int(matched.group('value'))
return str(value * 2)
s = 'A23G4HFD567'
print(re.sub('(?P\d+)', double, s))
使用匹配的子串来分割字符串,返回列表。
语法:
re.split(pattern, string[, maxsplit=0, flags=0])
参数:
数 描述 pattern 匹配的正则表达式 string 要匹配的字符串。 maxsplit 分割次数,maxsplit=1 分割一次,默认为 0,不限制次数。 flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
result = re.split(r"\s+", "This is a test")
print(result) # Output: ['This', 'is', 'a', 'test']
语法:
re.compile(pattern[, flags])
参数:
参数 描述 pattern 一个字符串形式的正则表达式 flags 可选,表示匹配模式,比如忽略大小写,多行模式等
import re
pattern = re.compile(r'\d+') # 用于匹配至少一个数字
m = pattern.match('one12twothree34four') # 查找头部,没有匹配
print( m )
m = pattern.match('one12twothree34four', 2, 10) # 从'e'的位置开始匹配,没有匹配
print( m )
m = pattern.match('one12twothree34four', 3, 10) # 从'1'的位置开始匹配,正好匹配
print( m ) # 返回一个 Match 对象
m.group(0) # 可省略 0
m.start(0) # 可省略 0
m.end(0) # 可省略 0
m.span(0) # 可省略 0
标志 | 描述 | 示例 |
re.IGNORECASE 或 re.I | 使匹配对大小写不敏感 | |
re.MULTILINE 或 re.M | 多行匹配,影响 ^ 和 $,使它们匹配字符串的每一行的开头和结尾。 | |
re.DOTALL 或 re.S: | 使 . 匹配包括换行符在内的任意字符。 | |
re.ASCII | 使 \w, \W, \b, \B, \d, \D, \s, \S 仅匹配 ASCII 字符 | |
re.VERBOSE 或 re.X | 忽略空格和注释,可以更清晰地组织复杂的正则表达式。 | |
import re
text = "Contact us at [email protected] or [email protected]"
emails = re.findall(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}", text)
print(emails) # Output: ['[email protected]', '[email protected]']
import re
text = "My old phone number was 123-456-7890."
new_text = re.sub(r"\d{3}-\d{3}-\d{4}", "XXX-XXX-XXXX", text)
print(new_text) # Output: My old phone number was XXX-XXX-XXXX.
import re
text = "apple, orange; banana: grape"
fruits = re.split(r"[,;:\s]+", text)
print(fruits) # Output: ['apple', 'orange', 'banana', 'grape']
.*
贪婪匹配示例print(re.findall("a.*d","a11b222d2d33"))
.*?
非贪婪匹配示例print(re.findall("a.*?d","a11b222d2d33"))
获取豆瓣top250的电影信息
# 拿到页面源代码 requests
# 使用re模块提取
import requests
import re
import csv
url = "https://movie.douban.com/top250"
head = {
"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36"
}
for j in range(0, 300, 25):
param = {
"start": j
}
res = requests.get(url, headers=head, params=param)
pageContent = res.text
# 解析数据
obj = re.compile(r'.*?.*?(?P.*?)'
r' .*?.*?
(?P.*?) .*'
r'/ (?P.*?).*?'
r' (?P.*?).*?'
r'(?P.*?)人评价 .*?', re.S)
# 打开文件,指定newline=''(对于Unix系统)或newline='\n'(对于Windows系统)
f = open("豆瓣top250.csv","a+",encoding="utf-8", newline="\n")
csvWriter = csv.writer(f)
for i in obj.finditer(pageContent) :
# print(i.group("moveName"),i.group("year").strip(),i.group("average"),i.group("num"))
dict = i.groupdict()
dict['year'] = dict['year'].strip()
dict['num'] = dict['num'].strip()
# dict['type'] = dict['type'].strip()
print(dict)
csvWriter.writerow(dict.values())
f.close()
更多示例:
Python之re模块详解 (超级无敌宇宙灭霸详细)_python re-CSDN博客
.*?