[TOC]
参考文章:
* https://www.jianshu.com/p/5295c5988b7f
## 正则表达式基础
re正则表达式模块就是字符串的匹配规则
### 常用的表达式规则
| 元字符 | 说明 |
| --- | --- |
| . | 代表任意字符 |
| | | 逻辑或操作符 |
| ^ | 匹配字符串的开头 |
| $ | 匹配字符串结束 |
| \[ \] | 匹配内部的任一字符或子表达式 |
| \[^\] | 对字符集和取非 |
| \- | 定义一个区间 |
| \\ | 对下一字符取非,通常是普通变特殊 |
| \* | 匹配前面的字符或子表达式0次或多次 |
| \*? | 惰性匹配上一个 |
| + | 匹配前一个字符或子表达式一次或多次 |
| +? | 惰性匹配上一个 |
| ? | 匹配前一个字符或子表达式0次或1次重复 |
| {n} | 匹配前一个字符或子表达式 |
| {m,n} | 匹配前一个字符或子表达式至少m次至多n次 |
| {n,} | 匹配前一个字符或者子表达式至少n次 |
| {n,}? | 前一个的惰性匹配 |
|\A | 只从字符开头匹配,同^|
|\Z | 匹配字符结尾,同$ |
|\d | 匹配数字0-9|
|\D | 匹配非数字|
|\w | 匹配[A-Za-z0-9]|
|\W | 匹配非[A-Za-z0-9]|
|s | 匹配空白字符、\t、\n、\r|
### 贪婪匹配和非贪婪匹配
* **贪婪匹配**
当正则表达式中包含能接受重复的限定符时,通常的行为是匹配尽可能多的字符,这被称为贪婪匹配。python的正则匹配默认情况是贪婪匹配:
```
>>> re.findall('a.*b','aabab')
['aabab']
```
* **非贪婪匹配**
非贪婪匹配就是匹配尽可能少的字符,使用?来表示非贪婪匹配,比如.\*?就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。
```
*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复
>>> re.findall('a.*?b','aabab')
['aab', 'ab']
>>>
```
### 分组匹配
1. 分组匹配的语法
()被括起来的表达式将作为分组。
```python
(?P<name>) 分组,除了原有的编号外再指定一个额外的别名name
(?P=name) 引用别名为<name>的分组匹配到字符串
(?:...) 分组的不捕获模式,计算索引时会跳过这个分组,取消优先级,相当于取消括号内分组(去掉括号)
\number 匹配和前面索引为number的分组捕获到的内容一样的字符串
(?=...) 顺序肯定环视,表示所在位置右侧能够匹配括号内正则
(?!...) 顺序否定环视,表示所在位置右侧不能匹配括号内正则
(?<=...) 逆序肯定环视,表示所在位置左侧能够匹配括号内正则
(?<!...) 逆序否定环视,表示所在位置左侧不能匹配括号内正则
(?(id/name)yes|no) 若前面指定id或name的分区匹配成功则执行yes处的正则,否则执行no处的正则
```
1. 前瞻后顾与环视
有些地方叫前瞻后顾,有些地方叫环视,说的都是一个意思.
```
前 瞻: exp1(?=exp2) exp1后面的内容要匹配exp2
负前瞻: exp1(?!exp2) exp1后面的内容不能匹配exp2
后 顾: (?<=exp2)exp1 exp1前面的内容要匹配exp2
负后顾: (?<!exp2)exp1 exp1前面的内容不能匹配exp2
例如:我们要查找hello,但是hello后面必须是world,正则表达式可以这样写:
"(hello)\s+(?=world)",用来匹配"hello wangxing"和"hello world"只能匹配到后者的hello
```
2. 分组匹配案例
```
num="371481199306143242"
s=re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})",num)
print(s)
print(s.groupdict())
结果:
<_sre.SRE_Match object; span=(0, 10), match='3714811993'>
{'province': '3714', 'city': '81', 'birthday': '1993'}
```
>此处用到了re的内置对象`groupdict`,详情见高级内置对象部分
## re正则模块语法
### re的常用方法语法
1. compile(pattern,flags=0):
编译正则表达式pattern进行并返回一个regex对象供其他方法使用
1. re.match(pattern,string,flags=0):
返回一个匹配对象,从字符串的开头开始匹配的
1. re.search(pattern,string,flags=0):
返回一个匹配对象,查找匹配正则表达式模式pattern的第一次
1. re.findall(pattern,string[,flags]):
返回一个列表,把所有匹配到的字符放到以列表中的元素返回
1. re.finditer(pattern,string[,flags]):
返回一个可迭代对象,和findall()相同,但返回的不是列表而是迭代器
1. re.split(pattern,string,max=0):
以匹配到的字符当做列表分隔符,最多分割max次。
1. re.sub(pattern,rep1,string,max=0):
返回一个字符串。把string中所有匹配正则表达式pattern的地方换成字符串rep1
1. re.fullmatch(pattern, string, flags=0)
整个字符串匹配成功就返回re object, 否则返回None
1. re.group(num=0):
返回全部匹配对象,或指定编号是num的子组。
1. re.groups():
返回一个包含全部匹配的子组的元组,如果没有成功匹配,就返回一个空元组。
### 语法参数解析
* pattern 正则表达式
* string 要匹配的字符串
* flags 标志位,用于控制正则表达式的匹配方式
### 常用flag标志
| 标志 | 含义 |
| --- | --- |
| re.S (DOTALL) | 使.(点)匹配包括换行在内的所有字符 |
| re.I(IGNORECASE) | 使匹配对大小写不敏感 |
| re.L(LOCALE) | 做本地化识别(locale-aware)匹配 |
| re.M(MULTILINE) | 多行匹配,影响^和$ |
| re.X(VERBOSE) | 能够使用 REs 的 verbose 状态,能被组织得更清晰易懂 |
| re.U | 根据Unicode字符集解析字符,这个标志影响\w,\W,\b,\B |
### 匹配对象的属性与方法
search、match等方法会返回一个匹配对象,其他方法还可能返回列表,可迭代对象等,这些返回的对象有一些内置方法可以使用,如下
* m.group(g, ...)
返回编号或者组名匹配到的内容,默认或者0表示整个表达式匹配到的内容,如果指定多个,就返回一个元组
* m.groupdict(default)
返回一个字典。字典的键是所有命名的组的组名,值为命名组捕获到的内容
如果有default参数,则将其作为那些没有参与匹配的组的默认值。
* m.groups(default)
返回一个元组。包含所有捕获到内容的子分组,从1开始,如果指定了default值,则这个值作为那些没有捕获到内容的组的值
* m.lastgroup()
匹配到内容的编号最高的捕获组的名称,如果没有或者没有使用名称则返回None(不常用)
* m.lastindex()
匹配到内容的编号最高的捕获组的编号,如果没有就返回None。
* m.start(g)
当前匹配对象的子分组是从字符串的那个位置开始匹配的,如果当前组没有参与匹配就返回-1
* m.end(g)
当前匹配对象的子分组是从字符串的那个位置匹配结束的,如果当前组没有参与匹配就返回-1
* m.span()
返回一个二元组,内容分别是m.start(g)和m.end(g)的返回值
* m.re()
产生这一匹配对象的正则表达式
* m.string()
传递给match或者search用于匹配的字符串
* m.pos()
搜索的起始位置。即字符串的开头,或者start指定的位置(不常用)
* m.endpos()
搜索的结束位置。即字符串的末尾位置,或者end指定的位置(不常用)
## 语法简单案例
**re.compile(pattern, flags=0)**
```
prog = re.compile(pattern)
result = prog.match(string)
```
**re.match(pattern, string, flags=0)**
从起始位置开始根据模型去字符串中匹配指定内容,匹配单个
```
import re
obj = re.match('\d+', '123uuasf')
if obj:
print obj.group()
```
**re.search(pattern, string, flags=0)**
根据模型去字符串中匹配指定内容,匹配单个
```
import re
obj = re.search('\d+', 'u123uu888asf')
if obj:
print obj.group()`
```
**re.findall(pattern, string, flags=0)**
match and search均用于匹配单值,即:只能匹配字符串中的一个,如果想要匹配到字符串中所有符合条件的元素,则需要使用 findall。
```
import re
obj = re.findall('\d+', 'fa123uu888asf')
print obj
```
**re.sub(pattern, repl, string, count=0, flags=0)**
用于替换匹配的字符串
```
>>>re.sub('[a-z]+','sb','武配齐是abc123',)
>>> re.sub('\d+','|', 'alex22wupeiqi33oldboy55',count=2)
'alex|wupeiqi|oldboy55'
```
相比于str.replace功能更加强大
**re.split(pattern, string, maxsplit=0, flags=0)**
```
>>>s='9-2*5/3+7/3*99/4*2998+10*568/14'
>>>re.split('[\*\-\/\+]',s)
['9', '2', '5', '3', '7', '3', '99', '4', '2998', '10', '568', '14']
>>> re.split('[\*\-\/\+]',s,3)
['9', '2', '5', '3+7/3*99/4*2998+10*568/14']
```
**re.fullmatch(pattern, string, flags=0)**
整个字符串匹配成功就返回re object, 否则返回None
```
re.fullmatch('\w+@\w+\.(com|cn|edu)',"alex@oldboyedu.cn")
```
## 常用正则表达式
```
1、匹配email地址:
[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?
2、匹配网址URL:
[a-zA-z]+://[^\s]*
3、匹配18位身份证号:
^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$
4、匹配年月日格式:
([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8])))
5、匹配整数:
^-?[1-9]\d*$
6、匹配正整数:
^[1-9]\d*$
7、匹配负整数:
^-[1-9]\d*$
8、匹配空白行:
\n\s*\r
```
## 总结
* 对于正则表达式的匹配功能,Python没有返回true和false的方法,但可以通过对match或者search方法的返回值是否是None来判断
* 对于正则表达式的搜索功能,如果只搜索一次可以使用search或者match方法返回的匹配对象得到,对于搜索多次可以使用finditer方法返回的可迭代对象来迭代访问
* 对于正则表达式的替换功能,可以使用正则表达式对象的sub或者subn方法来实现,也可以通过re模块方法sub或者subn来实现,区别在于模块的sub方法的替换文本可以使用一个函数来生成
* 对于正则表达式的分割功能,可以使用正则表达式对象的split方法,需要注意如果正则表达式对象有分组的话,分组捕获的内容也会放到返回的列表中
- 基础部分
- 基础知识
- 变量
- 数据类型
- 数字与布尔详解
- 列表详解list
- 字符串详解str
- 元组详解tup
- 字典详解dict
- 集合详解set
- 运算符
- 流程控制与循环
- 字符编码
- 编的小程序
- 三级菜单
- 斐波那契数列
- 汉诺塔
- 文件操作
- 函数相关
- 函数基础知识
- 函数进阶知识
- lambda与map-filter-reduce
- 装饰器知识
- 生成器和迭代器
- 琢磨的小技巧
- 通过operator函数将字符串转换回运算符
- 目录规范
- 异常处理
- 常用模块
- 模块和包相关概念
- 绝对导入&相对导入
- pip使用第三方源
- time&datetime模块
- random随机数模块
- os 系统交互模块
- sys系统模块
- shutil复制&打包模块
- json&pickle&shelve模块
- xml序列化模块
- configparser配置模块
- hashlib哈希模块
- subprocess命令模块
- 日志logging模块基础
- 日志logging模块进阶
- 日志重复输出问题
- re正则表达式模块
- struct字节处理模块
- abc抽象类与多态模块
- requests与urllib网络访问模块
- 参数控制模块1-optparse-过时
- 参数控制模块2-argparse
- pymysql数据库模块
- requests网络请求模块
- 面向对象
- 面向对象相关概念
- 类与对象基础操作
- 继承-派生和组合
- 抽象类与接口
- 多态与鸭子类型
- 封装-隐藏与扩展性
- 绑定方法与非绑定方法
- 反射-字符串映射属性
- 类相关内置方法
- 元类自定义及单例模式
- 面向对象的软件开发
- 网络-并发编程
- 网络编程SOCKET
- socket简介和入门
- socket代码实例
- 粘包及粘包解决办法
- 基于UDP协议的socket
- 文件传输程序实战
- socketserver并发模块
- 多进程multiprocessing模块
- 进程理论知识
- 多进程与守护进程
- 锁-信号量-事件
- 队列与生产消费模型
- 进程池Pool
- 多线程threading模块
- 进程理论和GIL锁
- 死锁与递归锁
- 多线程与守护线程
- 定时器-条件-队列
- 线程池与进程池(新方法)
- 协程与IO模型
- 协程理论知识
- gevent与greenlet模块
- 5种网络IO模型
- 非阻塞与多路复用IO实现
- 带着目标学python
- Pycharm基本使用
- 爬虫
- 案例-爬mzitu美女
- 案例-爬小说
- beautifulsoup解析模块
- etree中的xpath解析模块
- 反爬对抗-普通验证码
- 反爬对抗-session登录
- 反爬对抗-代理池
- 爬虫技巧-线程池
- 爬虫对抗-图片懒加载
- selenium浏览器模拟