[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瀏覽器模擬