参考文章:
【re — 正则表达式操作】
【正则表达式指南】
【Python 正则表达式 | 菜鸟教程】
【Python 正则表达式 | 极客教程】
【Python正则表达式详解 (超详细,看完必会!)】
# 导入 re 模块
import re
# 使用 match 方法进行匹配操作
# re.match() 能够匹配出以 xxx 开头的字符串
result = re.match(r'正则表达式', '被匹配的字符串')
if result:
# 如果上一步匹配到数据的话,可以使用 group 方法来提取数据
print(result.group())
else:
print('匹配失败')
需要注意的是:
Python 中字符串前面加上 r 表示原生字符串。与大多数编程语言相同,正则表达式里使用 “\” 作为转义字符,这就可能造成反斜杠困扰。Python 里的原生字符串很好地解决了这个问题,同时写出来的表达式也更直观。注意 r 只服务于 “\” ,不对其他进行转义。
字符 | 介绍 |
---|---|
^ |
匹配字符串的开头 |
$ |
匹配字符串的末尾 |
字符 | 介绍 |
---|---|
. |
匹配任意一个字符,除了换行符 \n |
[] |
匹配一个 [ ] 中列举的字符 |
[^] |
匹配除 [ ] 中列举的字符外的字符 |
\d |
匹配任何一个十进制数字,等价于字符类 [0-9] |
\D |
匹配任何一个非数字字符,等价于字符类 [^0-9] |
\s |
匹配任何一个空白字符,等价于字符类 [\t\n\r\f\v] |
\S |
匹配任何一个非空白字符,等价于字符类 [^\t\n\r\f\v] |
\w |
匹配任何一个字母与数字字符,以及下划线,等价于字符类 [a-zA-Z0-9_] |
\W |
匹配任何一个非字母与数字字符,以及非下划线,等价于字符类 [^a-zA-Z0-9_] |
\b |
匹配空字符串,但只在单词开始或结尾的位置 |
\B |
匹配空字符串,但仅限于它不在单词的开头或结尾的情况 |
\A |
匹配字符串开始 |
\Z |
匹配字符串结尾 |
\ 是转义特殊字符,\n 代表换行、\r 代表回车、\f 代表换页、\t 代表 Tab 键
通过用 ‘-’ 将两个字符连起来可以表示字符范围,比如:
除反斜杠外的特殊字符在 [ ] 中会失去其特殊含义,例如:[(+*)] 将匹配字符为 ( + * 或 ) 中的任何一个
字符 | 介绍 |
---|---|
* |
匹配前一个字符出现 0 次或者无限次 |
+ |
匹配前一个字符出现 1 次或者无限次 |
? |
匹配前一个字符出现 1 次或者 0 次 |
{m} |
匹配前一个字符出现 m 次 |
{m,n} |
匹配前一个字符出现从 m 至 n 次 |
{m,} |
匹配前一个字符出现至少 m 次 |
ab* 会匹配 ‘a’,‘ab’,或者 ‘a’ 后面跟随任意个 ‘b’
ab+ 会匹配 ‘a’ 后面跟随 1 个以上到任意个 ‘b’,它不会匹配 ‘a’
ab? 会匹配 ‘a’ 或者 ‘ab’
a{6} 将匹配 6 个 ‘a’ , 少于 6 个的话就会导致匹配失败
a{3,5} 将匹配 3 到 5 个 ‘a’
字符 | 介绍 |
---|---|
| | 如果 A 和 B 是正则表达式,A|B 将匹配任何与 A 或 B 匹配的字符串 |
() |
将括号中的字符作为一个分组 |
\num |
引用分组 num 匹配到的字符串 |
(?P |
分组所匹配到了的字符串可通过符号分组名称 name 来访问 |
(?P=name) |
匹配前面叫 name 的命名组中所匹配到的串 |
import re
email_list = ["[email protected]", "[email protected]", "[email protected]",
"[email protected]", "[email protected]", "[email protected]",
"[email protected]"]
for email in email_list:
ret = re.match(r"\w{4,20}@(163|126|qq)\.com$", email)
if ret:
print("%s 是符合规定的邮件地址 , 匹配后的结果是 : %s" % (email, ret.group()))
else:
print("%s 不符合要求" % email)
结果展示:
[email protected] 是符合规定的邮件地址 , 匹配后的结果是 : [email protected]
[email protected] 不符合要求
[email protected] 不符合要求
[email protected] 不符合要求
[email protected] 是符合规定的邮件地址 , 匹配后的结果是 : [email protected]
[email protected] 不符合要求
[email protected] 是符合规定的邮件地址 , 匹配后的结果是 : [email protected]
匹配 11 位不是以 4、7 结尾的手机号码:re.match(r"1\d{9}[0-35-68-9]$", tel)
提取区号和电话号码:ret = re.match(r"([^-]+)-(\d+)","010-12345678")
,此时 ret.group(1) = ‘010’ ,ret.group(2) = ‘12345678’ ,ret.group(0) 等价于 ret.group() 等于 ‘010-12345678’
匹配标签,例如:匹配
import re
texts = ['hello
', 'world
',
'hello'
]
def match():
for text in texts:
ret = re.match(r'<([a-zA-Z]*)><([a-zA-Z0-9]*)>(\w*)\2>\1>', text)
if ret:
print(f'匹配成功,标签为 {ret.group()},信息为 {ret.group(3)}')
else:
print(f'{text} 标签匹配失败')
if __name__ == '__main__':
match()
结果展示:
匹配成功,标签为 hello
,信息为 hello
world
标签匹配失败
hello 标签匹配失败
re.match(r'<(?P[a-zA-Z]*)><(?P[a-zA-Z0-9]*)>(\w*)(?P=name2)>(?P=name1)>', text)
函数 | 含义 |
---|---|
re.compile(pattern, flags=0) |
将正则表达式的样式编译为一个正则表达式对象(正则对象),可以用于匹配 |
re.search(pattern, string, flags=0) |
扫描整个字符串,返回第一个匹配项 |
re.match(pattern, string, flags=0) |
从字符串开始位置匹配正则表达式 |
re.fullmatch(pattern, string, flags=0) |
如果整个 string 与正则表达式 pattern 匹配,则返回相应的 Match |
re.split(pattern, string, maxsplit=0, flags=0) |
按匹配项分割字符串 |
re.findall(pattern, string, flags=0) |
返回字符串中所有匹配的子串 |
re.finditer(pattern, string, flags=0) |
针对正则表达式 pattern 在 string 里的所有非重叠匹配返回一个产生 Match 对象的迭代器 |
re.sub(pattern, repl, string, count=0, flags=0) |
替换字符串中所有匹配正则表达式的部分 |
re.subn(pattern, repl, string, count=0, flags=0) |
行为与 sub() 相同,但是返回一个元组,包含 (替换后的字符串, 替换次数) |
re.escape(pattern) |
转义 pattern 中的特殊字符,结果可直接用作匹配字符串 |
re.purge() |
清除正则表达式的缓存 |
result = re.match(pattern, string)
等价于 prog = re.compile(pattern)
和 result = prog.match(string)
。
re.split
函数中如果 maxsplit 非零,则最多进行 maxsplit 次分隔,剩下的字符全部返回到列表的最后一个元素。
需求:匹配出文章阅读的次数和点赞的次数。
import re
def find_second_match(pattern, text):
matches = re.finditer(pattern, text)
try:
next(matches) # 跳过第一个匹配项
second_match = next(matches) # 获取第二个匹配项
return second_match.group()
except StopIteration:
return None
if __name__ == '__main__':
p = r"\d+"
t = "阅读次数为 9999 , 点赞次数为 19999"
ret = re.search(p, t)
print(f'阅读次数为 {ret.group()} , 点赞次数为 {find_second_match(p, t)}')
结果展示:
阅读次数为 9999 , 点赞次数为 19999
import re
ret = re.findall(r"\d+", "read = 9999, thumbs up = 7890, collection = 12345")
print(f'阅读次数 {ret[0]} ,点赞次数 {ret[1]} ,收藏次数 {ret[2]}')
结果展示:
阅读次数 9999 ,点赞次数 7890 ,收藏次数 12345
【拓展】:分组()
内加入 ?:
可以避免只返回分组内的内容。
import re
if __name__ == '__main__':
s = 'hello world, now is 2020/7/20 18:48, 现在是 2020年7月20日18时48分。'
ret_s = re.sub(r'年|月', r'/', s)
ret_s = re.sub(r'日|分', r' ', ret_s)
ret_s = re.sub(r'时', r':', ret_s)
# hello world, now is 2020/7/20 18:48, 现在是 2020/7/20 18:48 。
print(ret_s)
# findall
com1 = re.compile(r'\d{4}/[01]?[0-9]/[1-3]?[0-9]\s(0[0-9]|1[0-9]|2[0-4])\:[0-5][0-9]')
ret1 = com1.findall(ret_s)
print(ret1[0]) # 18
# 加 ?:
com2 = re.compile(r'\d{4}/[01]?[0-9]/[1-3]?[0-9]\s(?:0[0-9]|1[0-9]|2[0-4])\:[0-5][0-9]')
ret2 = com2.findall(ret_s)
print(ret2[0]) # 2020/7/20 18:48
# search
ret3 = re.search(r'\d{4}/[01]?[0-9]/[1-3]?[0-9]\s(0[0-9]|1[0-9]|2[0-4])\:[0-5][0-9]', ret_s)
print(ret3.group()) # 2020/7/20 18:48
将匹配到的数据进行替换。
import re
def add(temp):
str_num = temp.group()
num = int(str_num) + 1
return str(num)
if __name__ == '__main__':
ret = re.sub(r"\d+", '998', "thumbs up = 997")
print(ret)
ret = re.sub(r"\d+", add, "thumbs up = 997")
print(ret)
ret = re.sub(r"\d+", lambda x: str(int(x.group()) + 1), "thumbs up = 997")
print(ret)
print('-' * 30)
# count 替换次数
text = "apple apple apple apple"
pattern = r"apple"
replacement = "orange"
new_text = re.sub(pattern, replacement, text, count=2)
print(new_text)
结果展示:
thumbs up = 998
thumbs up = 998
thumbs up = 998
------------------------------
orange orange apple apple
实体,只留下纯文本内容。import re
if __name__ == '__main__':
text = ('' + '\n' +
'岗位职责:
' + '\n' +
'完成推荐算法、数据统计、接口、后台等服务器端相关工作
' + '\n' +
'
' + '\n' +
'必备要求:
' + '\n' +
'良好的自我驱动力和职业素养,工作积极主动、结果导向
' + '\n' +
'
' + '\n' +
'技术要求:
' + '\n' +
'1、一年以上 Python 开发经验,掌握面向对象分析和设计,了解设计模式
' + '\n' +
'2、掌握 HTTP 协议,熟悉 MVC、MVVM 等概念以及相关 WEB 开发框架
' + '\n' +
'3、掌握关系数据库开发设计,掌握 SQL,熟练使用 MySQL/PostgreSQL 中的一种
' + '\n' +
'4、掌握 NoSQL、MQ,熟练使用对应技术解决方案
' + '\n' +
'5、熟悉 Javascript/CSS/HTML5,JQuery、React、Vue.js
' + '\n' +
'
' + '\n' +
'加分项:
' + '\n' +
'大数据,数理统计,机器学习,sklearn,高性能,大并发。
' + '\n' +
'')
# print(text)
sub_result = re.sub(r"<[^>]*>| ", "", text)
print(sub_result)
结果展示:
岗位职责:
完成推荐算法、数据统计、接口、后台等服务器端相关工作
必备要求:
良好的自我驱动力和职业素养,工作积极主动、结果导向
技术要求:
1、一年以上 Python 开发经验,掌握面向对象分析和设计,了解设计模式
2、掌握 HTTP 协议,熟悉 MVC、MVVM 等概念以及相关 WEB 开发框架
3、掌握关系数据库开发设计,掌握 SQL,熟练使用 MySQL/PostgreSQL 中的一种
4、掌握 NoSQL、MQ,熟练使用对应技术解决方案
5、熟悉 Javascript/CSS/HTML5,JQuery、React、Vue.js
加分项:
大数据,数理统计,机器学习,sklearn,高性能,大并发。
解析正则表达式:r"<[^>]*>| "
<[^>]*>
:匹配一对尖括号 < > 及其内部内容,且内容不包含 > 符号,表示匹配 HTML 标签,比如
|
:表示 “或” 操作符。
:匹配 HTML 的不间断空格实体
。
替换字符串是 “” ,即将匹配的内容替换为空字符串(删除)。
根据匹配进行切割字符串,并返回一个列表。需求:切割字符串 “info:xiaoZhang 33 shandong” 。
import re
ret = re.split(r":| ","info:xiaoZhang 33 shandong")
print(ret)
结果展示:
['info', 'xiaoZhang', '33', 'shandong']
Python 里数量词默认是贪婪的,即总是尝试匹配尽可能多的字符,而非贪婪则相反,总是尝试匹配尽可能少的字符。
可以在 * , ? , + , {m,n} 后面加上非贪婪操作符 ? ,该操作符要求正则匹配的字符越少越好,因而可以将贪婪转变为非贪婪。
Python 代码示例:
import re
if __name__ == '__main__':
s = "This is a number 234-235-22-423"
# 贪婪
print(re.match(r".+(\d+-\d+-\d+-\d+)", s).group(1))
print(re.match(r"aa(\d+)", "aa2343ddd").group(1))
print(re.match(r"aa(\d+)ddd", "aa2343ddd").group(1))
print('-' * 30)
# 非贪婪
print(re.match(r".+?(\d+-\d+-\d+-\d+)", s).group(1))
print(re.match(r"aa(\d+?)", "aa2343ddd").group(1))
print(re.match(r"aa(\d+?)ddd", "aa2343ddd").group(1))
结果展示:
4-235-22-423
2343
2343
------------------------------
234-235-22-423
2
2343
标志 | 介绍 |
---|---|
re.I |
使匹配对大小写不敏感 |
re.A |
不让 \w 匹配汉字 |
re.L |
做本地化识别(locale-aware)匹配 |
re.M |
多行匹配,影响 ^ 和 $ |
re.S |
使 . 匹配包括换行符 \n 在内的所有字符 |
re.U |
根据 Unicode 字符集解析字符,这个标志影响 \w \W \b \B |
re.X |
该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解 |
Python 代码示例:
import re
if __name__ == '__main__':
s1 = 'hello\nworld'
ret1 = re.match(r'hello.W', s1, re.S | re.I)
if ret1:
print(ret1.group()) # hello w
else:
print('no match')
print('-' * 15)
s2 = 'hello你好world'
ret2 = re.match(r'hello\w*', s2, re.A)
if ret2:
print(ret2.group()) # hello
else:
print('no match')