正则表达式概述
什么是正则表达式
正则表达式:(Regular Expression),是一些有特殊的字符和符号组成的字符串,主要用来进行高级的文本搜索、匹配、替代等功能。
第一个正则表达式
通过定义一个简单的正则表达式,然后在目标字符串中进行查询匹配的操作,完成第一个程序的编写,同时对于正则表达式又一个初步的了解和认知。
# 引入正则表达式模块
import re
# 目标字符串
s = 'food foo tonight'
# 正则表达式
r = r'foo'
# 在目标字符串中查询符合正则表达式的字符
res = re.findall(r, s)
# 打印结果 查询到两个数据# ['foo', 'foo']
print(res)
Syntax of Regex(正则表达式操作语法)
Base Syntax
正则表达式的核心就是匹配,匹配用到的也是字符串,对于正则表达式的理解就需要对正则表达式的语法有一个比较良好的熟悉度。下面针对正则表达式的常见操作,分成三个部分进行了简要描述,对正则表达式语法先有一个全面的了解。
基本正则语法
符号 | 描述 |
---|---|
literal | 匹配文本字面值 |
re1|re2 | 匹配文本字符re1或re2 |
^ | 匹配目标字符开头位置 |
$ | 匹配目标字符结束位置 |
. | 匹配任意一个字符(\n除外) |
? | 匹配任意一个字符出现0次或1次 |
+ | 匹配任意一个字符出现1次或n次 |
* | 匹配任意一个字符出现0次或n次 |
{m} | 匹配任意一个字符出现m次 |
{m,} | 匹配任意一个字符至少出现m次 |
{,n} | 匹配任意一个字符最多出现n次 |
{m,n} | 匹配任意一个至少出现m次,最多出现n次 |
[0-9] | 匹配任意一个0-9之间的数字 |
[^0-9] | 匹配任意一个非数字字符 |
[3-6] | 匹配任意一个3-6之间的数字 |
[0-10] | 匹配00或10两个数字 |
[a-z] | 匹配任意一个小写字母 |
[A-Z] | 匹配任意一个大写字符 |
[a-zA-Z] | 匹配任意一个字母 |
[a-zA-Z0-9_] | 匹配任意一个字母/数字/下划线 |
(..) | 匹配分组表达式 |
# coding:utf-8
import re
target = '''Are you new to Django or to programming? This is the place to start!
From scratch: Overview | Installation
Tutorial: Part 1: Requests and responses | Part 2: Models and the admin site
| Part 3:
Views and templates | Part 4: Forms and generic views | Part 5: Testing |
Part 6:
Static files | Part 7: Customizing the admin site
Advanced Tutorials: How to write reusable apps | Writing your first patch
for Django
'''
# 基本语法:字符匹配
reg1 = r"to"
print(re.findall(reg1, target))
# ['to', 'to', 'to', 'to', 'to', 'to', 'to']
# 基本语法:或者匹配
reg2 = r"Django|Part"
print(re.findall(reg2, target))
# ['Django', 'Part', 'Part', 'Part', 'Part', 'Part', 'Part', 'Part', 'Django']
# 基本语法:开头匹配
reg3 = r"^Are"
print(re.findall(reg3, target))
# ['Are']
# 基本语法:结尾匹配
reg4 = r"Django$"
print(re.findall(reg4, target))
# ['Django']
# 基本语法:任意字符匹配
reg5 = r"Ho."
print(re.findall(reg5, target))
# ['How']
# 基本语法:范围匹配?,匹配一个字符出现了0次或1次
reg6 = r"pr?"
print(re.findall(reg6, target))
# ['pr', 'p', 'p', 'p', 'p', 'p', 'p']
# 基本语法:范围匹配+,匹配一个字符出现了1次或n次
reg7 = r"pr+"
print(re.findall(reg7, target))
# ['pr']
# 基本语法:范围匹配*,匹配一个字符出现了0次或n次
reg8 = r"pr*"
print(re.findall(reg8, target))
# ['pr', 'p', 'p', 'p', 'p', 'p', 'p']
# 基本语法:范围匹配{m},匹配一个字符出现了m次
"""
范围匹配:
{m,n}:匹配一个字符至少出现m次,至多出现n此
{m,}:匹配一个字符至少出现m次,至多不限
{,n}:匹配一个字符至多出现n次,至少不限
"""
reg9 = r"l{2}"
print(re.findall(reg9, target))
# ['ll']
# 基本语法:范围匹配[0-9],匹配出现了一个0-9之间的数字
reg10 = r"[0-9]+"
print(re.findall(reg10, target))
# ['1', '2', '3', '4', '5', '6', '7']
# 基本语法:范围匹配[a-z]([A-Z]),匹配出现了一个a-z(A-Z)之间的小写(大写)字母
reg11 = r"[a-z]{10}"
print(re.findall(reg11, target))
# ['programmin', 'nstallatio', 'ustomizing']
# 基本语法:范围匹配[a-zA-Z0-9_],匹配一个字母、数字或下划线
reg12 = r"[a-zA-Z0-9_]{10}"
print(re.findall(reg12, target))
# ['programmin', 'Installati', 'Customizin']
分组查询
# coding:utf-8
import re
target = '''
<img src="./images/1.jpg"/>
<img src="./images/2.jpg"/>
<img src="./images/3.jpg"/>
<img src="./images/4.jpg"/>
<img src="./images/5.jpg"/>'''
# 正则表达式中添加分组语法
reg = r'<img\s+src="(.*)"/>'
res = re.finditer(reg, target)
for r in res:
# print(r.group())
print(r.group(1))
正则表达式:元字符
符号 | 描述 |
---|---|
\d | 匹配任意一个[0-9]的数字 |
\D | 匹配任意一个非数字字符 |
\s | 匹配任意一个空白字符(\n\t\r\v\f) |
\S | 匹配任意一个非空白字符 |
\w | 匹配任意一个字母/数字/下划线 |
\W匹配任意一个非字母/数字/下划线 | |
\b | 匹配任意一个单词的边界 |
转义字符,可以用于匹配正则中用到的字符 |
# coding:utf-8
import re
# 目标字符串
target = """Django community 11445 people, 164 countries, 3845 packages and projects."""
# 元字符:\d,匹配任意一个[0-9]的数字
reg1 = r"\d+"
print(re.findall(reg1, target))
# ['11445', '164', '3845']
# 元字符:\s,匹配任意一个空白字符
reg2 = r"\s+"
print(re.findall(reg2, target))
# [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
# 元字符:\b,匹配任意一个数字/字母/下划线
reg3 = r"\w{5}"
print(re.findall(reg3, target))
# ['Djang', 'commu', '11445', 'peopl', 'count', 'packa', 'proje']
# 元字符:,匹配任意一个单词的边界
reg4 = r"\ban."
print(re.findall(reg4, target))
# ['and']
正则表达式:零宽断言
符号 | 描述 |
---|---|
(?reg) | 特殊标记参数 |
(?:reg) | 匹配不用保存的分组 |
(?P<name>reg) | 匹配到分组结果命名为name |
(?P=name) | 注释(?P<name>reg)前的文本 |
(?#content) | 注释 |
(?=reg) | 正向前视断言 |
(?!reg) | 负向前视断言 |
(?<=reg) | 正向后视断言 |
(?<!reg) | 负向后视断言 |
(?(id/name)Yre1/Nre2) | 条件断言分组 |
# coding:utf-8
import re
# 目标字符串
target = 'aahelloworldbbhellojerryjerryup'
# 零宽断言:正向前视断言
reg1 = r'.{2}hello(?=world)'
res = re.finditer(reg1, target)
for r in res:
print(r.group()) # aahello
reg2 = r'.{2}hello(?!world)'
res = re.finditer(reg2, target)
for r in res:
print(r.group()) # bbhello
reg3 = r'(?<=hello)jerry.{2}'
res = re.finditer(reg3, target)
for r in res:
print(r.group()) # jerryje
reg4 = r'(?<!hello)jerry.{2}'
res = re.finditer(reg4, target)
for r in res:
print(r.group()) # jerryup
贪婪匹配 & 懒惰匹配
贪婪模式和懒惰模式(非贪婪模式)是在正则操作过程中,需要严格注意的一个问题,如果操作不当的话很容易在匹配过程中得到非正常数据或者垃圾数据。
什么是贪婪和非贪婪模式
贪婪模式:在正则表达式匹配成功的前提下,尽可能多的匹配结果数据
非贪婪模式:在正则表达式匹配成功的前提下,尽可能少的匹配结果数据
贪婪和非贪婪模式
# coding:utf-8
import re
target = "<div>hello</div><p>world</p><div>regular expression</div>"
# 正则表达式:贪婪匹配
reg = re.compile(r"<div>.*</div>")
# 查询数据
res = reg.search(target)
print(res.group())
# <div>hello</div><p>world</p><div>regular expression</div>
# 正则表达式:懒惰匹配(非贪婪匹配)
reg = re.compile(r"<div>.*?</div>")
# 查询数据
res = reg.search(target)
print(res.group())
# <div>hello</div>
pyhton中的正则
re正则模块
python中通过标准库re模块对于正则表达式进行良好的技术支持。
为什么使用正则表达式
正则表达式本身就是对于字符串的高效处理,尽管字符串本身也内置了一些操作函数,但是相对于较为复杂的需求,通过正则表达式的操作更加灵活并且效率更高。
正则表达式在程序中的主要应用,有以下几个方面:
匹配:测试一个字符串是否符合正则表达式语法,返回 True 或者 False
获取:从目标字符串中,提取符合正则表达式语法的字符数据
替换:在目标字符串中查询符合正则语法的字符,并替换成指定的字符串
分割:按照符合正则表达式的语法字符对目标字符串进行分割
创建正则表达式的方式
python中有两种方式可以创建正则表达式的匹配对象,两种方式使用都较为广泛,具体满足开发人员所在的团队的开发规范即可。
隐式创建:通过一个普通字符串,直接创建正则表达式
要求:必须通过re模块的函数调用才能正常编译执行
import re
# 创建一个正则表达式
reg = r"\bfoo\b"
# 从目标字符串中提取数据
result = re.findall(reg, target_str)
显式创建:通过内建函数compile()编译创建一个正则表达式对象
要求:可以通过调用该类型的方法,完成字符串的操作
import re
pattern = re.compile("\\bfoo\\b")
pattern.findall(target_str)
简要操作案例
# coding:utf-8
import re
target = "helloworldhelloregexp"
# 1.函数
reg1 = r"(?<=hello).{3}"
print(re.findall(reg1, target))
# ['wor', 'reg']
# 2.对象
reg2 = re.compile(r"(?<=hello).{3}")
print(reg2.findall(target))
# ['wor', 'reg']
re模块常用方法
常用方法
常用方法 | 描述 |
---|---|
re.findall(s, start, end) | 返回(指定位置)查询到结果内容的列表 |
re.finditer(s, start, end) | 返回(指定位置)查询到结果匹配对象的生成器 |
re.search(s, start, end) | 返回(指定位置)第一次查询到的匹配对象 |
re.match(s, start, end) | 返回(指定位置)从第一个字符匹配到的结果 |
re.sub(s, r, c) | 使用r替换字符串中所有匹配的数据,c是替换次数 |
re.subn(s, r, c) | 使用r替换字符串中所有匹配的数据,c是替换次数 |
re.split(s, m) | 使用正则表达式拆分字符串,m是拆分次数 |
简单示例
# coding:utf-8
import re
target = "helloworldhellojerryhelloregularexpression"
# 定义正则表达式
reg = r"hello"
# findall()
print(re.findall(reg, target))
# ['hello', 'hello', 'hello']
# finditer()
res = re.finditer(reg, target)
for r in res:
print(r.group())
# hello
# hello
# hello
# search()
res = re.search(reg, target)
print(res)
# <_sre.SRE_Match object; span=(0, 5), match='hello'>
# match()
res = re.match(reg, target)
print(res)
# <_sre.SRE_Match object; span=(0, 5), match='hello'>
# sub()
res = re.sub(reg, "**", target)
print(res)
# **world**jerry**regularexpression
# subn()
res = re.subn(reg, "**", target)
print(res)
# ('**world**jerry**regularexpression', 3)
# split()
res = re.split(reg, target)
print(res)
# ['', 'world', 'jerry', 'regularexpression']