'python小課堂23 - 正則表達式(一)'

Python PHP Java 程序員 網絡爬蟲 咪哥雜談 2019-09-12
"

前言

今天來介紹一下Python的正則表達式。先來看下定義,何為正則表達式?

正則表達式是一個特殊的字符序列,一個字符串是否與我們給定的這個字符序列相匹配。正則最重要的功能就是處理字符串,例如檢索你在某一段字符串中的特定單詞,或者將原來某個位置的特定字符換成你想要的字符。而對於爬蟲來說,正則表達式是必不可少的技能之一,要想正確提取源代碼中你想要的信息內容,一般來說都會用到正則。

Python的re模塊初體驗

這裡用例子來假設一個場景吧...現在你正打算轉行踏入程序員的領域,然而面臨的第一個問題就是選擇一個主修語言來作為你轉行後的學習動力。於是有個字符串language="Java,Python,Go,Js,C,C++,PHP",你下定決心要學Python,於是讓你判斷Python這門語言是否在這個字符串中存在!你會怎麼做呢?

方案一:

通過python內置函數string.index('Python')


language = 'Java,Python,Go,Js,C,C++,PHP'
print(language.index('Python'))
>>> 5

結果說明在索引下標第5位開始,尋找到了Python字符串。

方案二:

通過in關鍵詞


language = 'Java,Python,Go,Js,C,C++,PHP'
print('Python' in language)
>>> True

結果說明Python字符串存在於language中。

方案三:

通過re模塊,需要import re。


import re
language = 'Java,Python,Go,Js,C,C++,PHP'
"""
re.findall(pattern, string, flags=0):
必填的兩個參數:
第一個參數是正則表達式的模式;
第二個參數是原字符串
選填參數: flags ,傳入例如忽略大小寫的官方參數
返回的結果是: list
"""
result = re.findall('Python',language)
print(result)
>>> ['Python']

大家可以仔細看下代碼,註釋已經寫得很清楚啦....使用re.findall,見名知意,是查找到所有匹配到的,所以返回的肯定是list。不信的話,我們將代碼修改一下,在language裡多加一個Python,看下結果如何:

"

前言

今天來介紹一下Python的正則表達式。先來看下定義,何為正則表達式?

正則表達式是一個特殊的字符序列,一個字符串是否與我們給定的這個字符序列相匹配。正則最重要的功能就是處理字符串,例如檢索你在某一段字符串中的特定單詞,或者將原來某個位置的特定字符換成你想要的字符。而對於爬蟲來說,正則表達式是必不可少的技能之一,要想正確提取源代碼中你想要的信息內容,一般來說都會用到正則。

Python的re模塊初體驗

這裡用例子來假設一個場景吧...現在你正打算轉行踏入程序員的領域,然而面臨的第一個問題就是選擇一個主修語言來作為你轉行後的學習動力。於是有個字符串language="Java,Python,Go,Js,C,C++,PHP",你下定決心要學Python,於是讓你判斷Python這門語言是否在這個字符串中存在!你會怎麼做呢?

方案一:

通過python內置函數string.index('Python')


language = 'Java,Python,Go,Js,C,C++,PHP'
print(language.index('Python'))
>>> 5

結果說明在索引下標第5位開始,尋找到了Python字符串。

方案二:

通過in關鍵詞


language = 'Java,Python,Go,Js,C,C++,PHP'
print('Python' in language)
>>> True

結果說明Python字符串存在於language中。

方案三:

通過re模塊,需要import re。


import re
language = 'Java,Python,Go,Js,C,C++,PHP'
"""
re.findall(pattern, string, flags=0):
必填的兩個參數:
第一個參數是正則表達式的模式;
第二個參數是原字符串
選填參數: flags ,傳入例如忽略大小寫的官方參數
返回的結果是: list
"""
result = re.findall('Python',language)
print(result)
>>> ['Python']

大家可以仔細看下代碼,註釋已經寫得很清楚啦....使用re.findall,見名知意,是查找到所有匹配到的,所以返回的肯定是list。不信的話,我們將代碼修改一下,在language裡多加一個Python,看下結果如何:

python小課堂23 - 正則表達式(一)

Python正則表達式的原理性概念

這個標題起的名字有些拗口,因為我找不到好的概括詞語了,現在就來解釋一下吧....我們通過re模塊來判斷了一個字符串包含不包含與原始字符串,實際上這種用法是沒有意義的,真正的正則表達式用法場景,應該是依賴於規則!

1.普通字符和元字符

還是舉例說明,還是上邊找工作的那堆語言,假設每門語言的分割,我不用逗號進行分割了,我將各種公共電話號碼隨機插入來代替逗號,於是得到language="Java110Python120Go119Js4399C999C++666PHP"。

需求變更了,現在讓你提取出電話號碼!如何去做呢?


import re
language="Java110Python120Go119Js4399C999C++666PHP"
"""
re.findall(pattern, string, flags=0):
必填的兩個參數:
第一個參數是正則表達式的模式;
第二個參數是原字符串
選填參數: flags,傳入例如忽略大小寫的官方參數
返回的結果是: list
"""
result = re.findall('\\d',language)
print(result)
>>> ['1', '1', '0', '1', '2', '0', '1', '1', '9', '4', '3', '9', '9', '9', '9', '9', '6', '6', '6']

由於每個數字都不近相同,你可以用一堆數字去寫,但是比較麻煩。若換成字符,難不成還寫滿了你要匹配的字符嗎?所以這裡提出兩個概念:普通字符和元字符。

普通字符:re.findall('Python',language)中的'Python',就是普通字符。 元字符:re.findall('\\d',language)中的'\\d',就是元字符。

所謂的普通字符,就是你寫死了的固定字符,而元字符則不一樣,它代表的是一類的字符,而我現在寫的'\\d'的含義就是匹配所有數字。需要注意的是,普通字符和元字符是在正則表達式中可以混合使用的!

而我這裡不會詳細的介紹每個元字符的用法,重要的是自己查閱相關文檔的方法,而非死記硬背這些元字符的含義,可以用到的時候再去查即可。這裡給出相關圖吧,有興趣的可以看下:

"

前言

今天來介紹一下Python的正則表達式。先來看下定義,何為正則表達式?

正則表達式是一個特殊的字符序列,一個字符串是否與我們給定的這個字符序列相匹配。正則最重要的功能就是處理字符串,例如檢索你在某一段字符串中的特定單詞,或者將原來某個位置的特定字符換成你想要的字符。而對於爬蟲來說,正則表達式是必不可少的技能之一,要想正確提取源代碼中你想要的信息內容,一般來說都會用到正則。

Python的re模塊初體驗

這裡用例子來假設一個場景吧...現在你正打算轉行踏入程序員的領域,然而面臨的第一個問題就是選擇一個主修語言來作為你轉行後的學習動力。於是有個字符串language="Java,Python,Go,Js,C,C++,PHP",你下定決心要學Python,於是讓你判斷Python這門語言是否在這個字符串中存在!你會怎麼做呢?

方案一:

通過python內置函數string.index('Python')


language = 'Java,Python,Go,Js,C,C++,PHP'
print(language.index('Python'))
>>> 5

結果說明在索引下標第5位開始,尋找到了Python字符串。

方案二:

通過in關鍵詞


language = 'Java,Python,Go,Js,C,C++,PHP'
print('Python' in language)
>>> True

結果說明Python字符串存在於language中。

方案三:

通過re模塊,需要import re。


import re
language = 'Java,Python,Go,Js,C,C++,PHP'
"""
re.findall(pattern, string, flags=0):
必填的兩個參數:
第一個參數是正則表達式的模式;
第二個參數是原字符串
選填參數: flags ,傳入例如忽略大小寫的官方參數
返回的結果是: list
"""
result = re.findall('Python',language)
print(result)
>>> ['Python']

大家可以仔細看下代碼,註釋已經寫得很清楚啦....使用re.findall,見名知意,是查找到所有匹配到的,所以返回的肯定是list。不信的話,我們將代碼修改一下,在language裡多加一個Python,看下結果如何:

python小課堂23 - 正則表達式(一)

Python正則表達式的原理性概念

這個標題起的名字有些拗口,因為我找不到好的概括詞語了,現在就來解釋一下吧....我們通過re模塊來判斷了一個字符串包含不包含與原始字符串,實際上這種用法是沒有意義的,真正的正則表達式用法場景,應該是依賴於規則!

1.普通字符和元字符

還是舉例說明,還是上邊找工作的那堆語言,假設每門語言的分割,我不用逗號進行分割了,我將各種公共電話號碼隨機插入來代替逗號,於是得到language="Java110Python120Go119Js4399C999C++666PHP"。

需求變更了,現在讓你提取出電話號碼!如何去做呢?


import re
language="Java110Python120Go119Js4399C999C++666PHP"
"""
re.findall(pattern, string, flags=0):
必填的兩個參數:
第一個參數是正則表達式的模式;
第二個參數是原字符串
選填參數: flags,傳入例如忽略大小寫的官方參數
返回的結果是: list
"""
result = re.findall('\\d',language)
print(result)
>>> ['1', '1', '0', '1', '2', '0', '1', '1', '9', '4', '3', '9', '9', '9', '9', '9', '6', '6', '6']

由於每個數字都不近相同,你可以用一堆數字去寫,但是比較麻煩。若換成字符,難不成還寫滿了你要匹配的字符嗎?所以這裡提出兩個概念:普通字符和元字符。

普通字符:re.findall('Python',language)中的'Python',就是普通字符。 元字符:re.findall('\\d',language)中的'\\d',就是元字符。

所謂的普通字符,就是你寫死了的固定字符,而元字符則不一樣,它代表的是一類的字符,而我現在寫的'\\d'的含義就是匹配所有數字。需要注意的是,普通字符和元字符是在正則表達式中可以混合使用的!

而我這裡不會詳細的介紹每個元字符的用法,重要的是自己查閱相關文檔的方法,而非死記硬背這些元字符的含義,可以用到的時候再去查即可。這裡給出相關圖吧,有興趣的可以看下:

python小課堂23 - 正則表達式(一)

"

前言

今天來介紹一下Python的正則表達式。先來看下定義,何為正則表達式?

正則表達式是一個特殊的字符序列,一個字符串是否與我們給定的這個字符序列相匹配。正則最重要的功能就是處理字符串,例如檢索你在某一段字符串中的特定單詞,或者將原來某個位置的特定字符換成你想要的字符。而對於爬蟲來說,正則表達式是必不可少的技能之一,要想正確提取源代碼中你想要的信息內容,一般來說都會用到正則。

Python的re模塊初體驗

這裡用例子來假設一個場景吧...現在你正打算轉行踏入程序員的領域,然而面臨的第一個問題就是選擇一個主修語言來作為你轉行後的學習動力。於是有個字符串language="Java,Python,Go,Js,C,C++,PHP",你下定決心要學Python,於是讓你判斷Python這門語言是否在這個字符串中存在!你會怎麼做呢?

方案一:

通過python內置函數string.index('Python')


language = 'Java,Python,Go,Js,C,C++,PHP'
print(language.index('Python'))
>>> 5

結果說明在索引下標第5位開始,尋找到了Python字符串。

方案二:

通過in關鍵詞


language = 'Java,Python,Go,Js,C,C++,PHP'
print('Python' in language)
>>> True

結果說明Python字符串存在於language中。

方案三:

通過re模塊,需要import re。


import re
language = 'Java,Python,Go,Js,C,C++,PHP'
"""
re.findall(pattern, string, flags=0):
必填的兩個參數:
第一個參數是正則表達式的模式;
第二個參數是原字符串
選填參數: flags ,傳入例如忽略大小寫的官方參數
返回的結果是: list
"""
result = re.findall('Python',language)
print(result)
>>> ['Python']

大家可以仔細看下代碼,註釋已經寫得很清楚啦....使用re.findall,見名知意,是查找到所有匹配到的,所以返回的肯定是list。不信的話,我們將代碼修改一下,在language裡多加一個Python,看下結果如何:

python小課堂23 - 正則表達式(一)

Python正則表達式的原理性概念

這個標題起的名字有些拗口,因為我找不到好的概括詞語了,現在就來解釋一下吧....我們通過re模塊來判斷了一個字符串包含不包含與原始字符串,實際上這種用法是沒有意義的,真正的正則表達式用法場景,應該是依賴於規則!

1.普通字符和元字符

還是舉例說明,還是上邊找工作的那堆語言,假設每門語言的分割,我不用逗號進行分割了,我將各種公共電話號碼隨機插入來代替逗號,於是得到language="Java110Python120Go119Js4399C999C++666PHP"。

需求變更了,現在讓你提取出電話號碼!如何去做呢?


import re
language="Java110Python120Go119Js4399C999C++666PHP"
"""
re.findall(pattern, string, flags=0):
必填的兩個參數:
第一個參數是正則表達式的模式;
第二個參數是原字符串
選填參數: flags,傳入例如忽略大小寫的官方參數
返回的結果是: list
"""
result = re.findall('\\d',language)
print(result)
>>> ['1', '1', '0', '1', '2', '0', '1', '1', '9', '4', '3', '9', '9', '9', '9', '9', '6', '6', '6']

由於每個數字都不近相同,你可以用一堆數字去寫,但是比較麻煩。若換成字符,難不成還寫滿了你要匹配的字符嗎?所以這裡提出兩個概念:普通字符和元字符。

普通字符:re.findall('Python',language)中的'Python',就是普通字符。 元字符:re.findall('\\d',language)中的'\\d',就是元字符。

所謂的普通字符,就是你寫死了的固定字符,而元字符則不一樣,它代表的是一類的字符,而我現在寫的'\\d'的含義就是匹配所有數字。需要注意的是,普通字符和元字符是在正則表達式中可以混合使用的!

而我這裡不會詳細的介紹每個元字符的用法,重要的是自己查閱相關文檔的方法,而非死記硬背這些元字符的含義,可以用到的時候再去查即可。這裡給出相關圖吧,有興趣的可以看下:

python小課堂23 - 正則表達式(一)

python小課堂23 - 正則表達式(一)

以上圖片原址: https://baike.baidu.com/item/正則表達式/1700215?fr=aladdin#3

具體使用可以自行百度查看。

2. 字符集

在上面的例子中,我們可以看到,正則表達式匹配完的list得到的都是一個個拆分的字符,而所謂的字符集就是匹配出來的字符集合,也就是多個字符。如下面的例子:


import re
words = "abz,acz,adz,aez,afz"
result = re.findall('a[bcd]z', words)
print(result)
>>> ['abz', 'acz', 'adz']

若想匹配到原字符串中的多個字符,我們可以用[]這樣的形式來匹配多個符合的內容,而[]中的元素相互之間是的關係。a,z來限定邊界, [bcd] 則是匹配a,z中間符合的bcd的元素,所以最終得到的結果如上。


import re
words = "abz,acz,adz,aez,afz"
result = re.findall('a[^bcd]z', words)
print(result)
>>> ['aez', 'afz']

若在字符集的正則規定前,加上^則是代表取反的意思,可以看到結果,不匹配bcd,最終結果得到的是e,f。

當然還有一種寫法是下面這樣:


import re
words = "abz,acz,adz,aez,afz"
result = re.findall('a[b-e]z', words)
print(result)
>>> ['abz', 'acz', 'adz', 'aez']

用 - 也可以來表示一個範圍,比如A-Z,a-z,0-9等....

3. 數量詞


import re
words = "I am learning Pythonnnnnn, that 's awesome!"
result = re.findall('[a-z]{4}', words)
print(result)
>>> ['lear', 'ning', 'ytho', 'nnnn', 'that', 'awes']

在字符集的基礎上,我們如果想限定多少長度的字符,可以通過{}來限定匹配字符集的長度,當我寫入4的時候,可以看到從左到右,只有當相鄰字符組成的長度為4時,才會被匹配到。

然而這樣匹配是沒有實際意義的,我現在需要的是將每個詞語拆分並且匹配到,於是有了下面的寫法:


import re
words = "I am learning Pythonnnnnn, that 's awesome!"
result = re.findall('[a-zA-Z]{1,11}', words)
print(result)
>>> ['I', 'am', 'learning', 'Pythonnnnnn', 'that', 's', 'awesome']

{最短匹配長度,最長匹配長度},在配合上字符集的正則寫法,既可拆分出原有的單詞,注意的是[a-zA-Z] 這裡用到了組合的寫法,匹配字符是符合大小寫a-z的。

大家有沒有注意到一個點,就是在數量詞這裡,我對原字符串進行正則匹配,取得長度是1~11位,那麼在am時候就已經符合一位長度了,即字母a,為什麼沒有被單獨匹配出來作為結果呢?這裡就涉及到下面要說的正則表達式的貪婪模式與非貪婪模式了。

正則表達式的貪婪與非貪婪模式

貪婪模式:意如其名,貪婪嘛,就是要多多多!多匹配既是王道!

非貪婪模式:與貪婪模式相反唄,即少匹配就是王道!

對應上面的數量詞案例時,數量詞若是採用範圍取長度時,則是默認使用貪婪模式,即多多匹配,所以才會看到能匹配到字符集長度多的單詞。而Python默認傾向於是貪婪模式的!

1. “?” 匹配0次或者1次

在實際的應用中,我們也會遇到非貪婪的情況,即少匹配,那麼如何書寫呢?


import re
words = "I am learning Pythonnnnnn, that 's awesome!"
result = re.findall('[a-zA-Z]{1,11}?', words)
print(result)
>>> ['I', 'a', 'm', 'l', 'e', 'a', 'r', 'n', 'i', 'n', 'g', 'P', 'y', 't', 'h', 'o', 'n', 'n', 'n', 'n', 'n', 'n', 't', 'h', 'a', 't', 's', 'a', 'w', 'e', 's', 'o', 'm', 'e']

只需要在數量詞後面加一個?即可。代表的是匹配前面的數量詞0次或者1次。

特殊的小技巧:?一般可以來去掉字符後面的重複項,例如原字符串:"Pythonnnnn",可以用 'Python?' 得到Python, 這點自己可以思考並實驗下。

2. “*” 匹配0次或者無限次

下面這段代碼,你認為會打印出什麼樣的結果呢?


import re
words = "I am learning Pytho,Python,Pythonnnnnn, that 's awesome!"
result = re.findall('Pytho*', words)
print(result)

輸出結果:


>>> ['Pytho', 'Pytho', 'Pytho']

因為在原字符串中匹配到o,後面就截止了。

若是這樣呢:


import re
words = "I am learning Pytho,Python,Pythonnnnnn, that 's awesome!"
result = re.findall('Python*', words)
print(result)
#輸出結果
>>> ['Pytho', 'Python', 'Pythonnnnnn']

匹配 * 號的前一個字符無限次,所以有多少n,就會被匹配到多少n。為什麼Pytho也能被匹配到呢?因為 * 號代表的是前面的字符匹配到0次也是可以的!所以pytho也會被匹配到,這裡需要注意。

3. “+” 匹配1次或者無限次


import re
words = "I am learning Pytho,Python,Pythonnnnnn, that 's awesome!"
result = re.findall('Python+', words)
print(result)
# 輸出結果
>>> ['Python', 'Pythonnnnnn']

+號是匹配前面的字符至少一次,或者n次。所以不會匹配到Pytho!

4. “.” 匹配除換行符\\n之外的其他所有字符


import re
words = "Python \\n !@#%%$*&(%)"
result = re.findall('.', words)
print(result)
>>> ['P', 'y', 't', 'h', 'o', 'n', ' ', ' ', '!', '@', '#', '%', '%', '$', '*', '&', '(', '%', ')']

可以看到,除了\\n以外的字符都匹配到了,包括空格以及其他奇怪的字符~

正則表達式組的概念

在說組之前,再來介紹一個正則的用法:

^: 匹配原字符串的首位置開始

$: 匹配原字符串的尾位置結束

如下事例:


import re
words = "110120119999"
result = re.findall('^\\d{1,9}$', words)
print(result)
>>> []

因為^和$限定了原始字符串的頭和尾,從原始字符串中匹配1~9位長度的數字,並且是從頭到尾的去匹配,並沒有長度為9的數字,所以匹配出來是空的。

正則表達式組的概念:還記得之前python的基礎數據類型元組嗎?正則中的組,與字符集恰好相反,字符集中匹配的字符之間是或的關係,而組中匹配的字符之間則是與的關係。

場景如下,我現在想匹配整個hungry!!而若是通過字符匹配的話方法:


import re
words = "I'm hungry!!hungry!!hungry!!...."
result = re.findall('hungry!!{3}', words)
print(result)
>>> []

可以看到,什麼也沒匹配到,因為現在寫的意思是匹配前面是hungry!!且最後一個歎號長度為3個,也就是說如果字符串中有hungry!!!!,即可匹配到。

"

前言

今天來介紹一下Python的正則表達式。先來看下定義,何為正則表達式?

正則表達式是一個特殊的字符序列,一個字符串是否與我們給定的這個字符序列相匹配。正則最重要的功能就是處理字符串,例如檢索你在某一段字符串中的特定單詞,或者將原來某個位置的特定字符換成你想要的字符。而對於爬蟲來說,正則表達式是必不可少的技能之一,要想正確提取源代碼中你想要的信息內容,一般來說都會用到正則。

Python的re模塊初體驗

這裡用例子來假設一個場景吧...現在你正打算轉行踏入程序員的領域,然而面臨的第一個問題就是選擇一個主修語言來作為你轉行後的學習動力。於是有個字符串language="Java,Python,Go,Js,C,C++,PHP",你下定決心要學Python,於是讓你判斷Python這門語言是否在這個字符串中存在!你會怎麼做呢?

方案一:

通過python內置函數string.index('Python')


language = 'Java,Python,Go,Js,C,C++,PHP'
print(language.index('Python'))
>>> 5

結果說明在索引下標第5位開始,尋找到了Python字符串。

方案二:

通過in關鍵詞


language = 'Java,Python,Go,Js,C,C++,PHP'
print('Python' in language)
>>> True

結果說明Python字符串存在於language中。

方案三:

通過re模塊,需要import re。


import re
language = 'Java,Python,Go,Js,C,C++,PHP'
"""
re.findall(pattern, string, flags=0):
必填的兩個參數:
第一個參數是正則表達式的模式;
第二個參數是原字符串
選填參數: flags ,傳入例如忽略大小寫的官方參數
返回的結果是: list
"""
result = re.findall('Python',language)
print(result)
>>> ['Python']

大家可以仔細看下代碼,註釋已經寫得很清楚啦....使用re.findall,見名知意,是查找到所有匹配到的,所以返回的肯定是list。不信的話,我們將代碼修改一下,在language裡多加一個Python,看下結果如何:

python小課堂23 - 正則表達式(一)

Python正則表達式的原理性概念

這個標題起的名字有些拗口,因為我找不到好的概括詞語了,現在就來解釋一下吧....我們通過re模塊來判斷了一個字符串包含不包含與原始字符串,實際上這種用法是沒有意義的,真正的正則表達式用法場景,應該是依賴於規則!

1.普通字符和元字符

還是舉例說明,還是上邊找工作的那堆語言,假設每門語言的分割,我不用逗號進行分割了,我將各種公共電話號碼隨機插入來代替逗號,於是得到language="Java110Python120Go119Js4399C999C++666PHP"。

需求變更了,現在讓你提取出電話號碼!如何去做呢?


import re
language="Java110Python120Go119Js4399C999C++666PHP"
"""
re.findall(pattern, string, flags=0):
必填的兩個參數:
第一個參數是正則表達式的模式;
第二個參數是原字符串
選填參數: flags,傳入例如忽略大小寫的官方參數
返回的結果是: list
"""
result = re.findall('\\d',language)
print(result)
>>> ['1', '1', '0', '1', '2', '0', '1', '1', '9', '4', '3', '9', '9', '9', '9', '9', '6', '6', '6']

由於每個數字都不近相同,你可以用一堆數字去寫,但是比較麻煩。若換成字符,難不成還寫滿了你要匹配的字符嗎?所以這裡提出兩個概念:普通字符和元字符。

普通字符:re.findall('Python',language)中的'Python',就是普通字符。 元字符:re.findall('\\d',language)中的'\\d',就是元字符。

所謂的普通字符,就是你寫死了的固定字符,而元字符則不一樣,它代表的是一類的字符,而我現在寫的'\\d'的含義就是匹配所有數字。需要注意的是,普通字符和元字符是在正則表達式中可以混合使用的!

而我這裡不會詳細的介紹每個元字符的用法,重要的是自己查閱相關文檔的方法,而非死記硬背這些元字符的含義,可以用到的時候再去查即可。這裡給出相關圖吧,有興趣的可以看下:

python小課堂23 - 正則表達式(一)

python小課堂23 - 正則表達式(一)

以上圖片原址: https://baike.baidu.com/item/正則表達式/1700215?fr=aladdin#3

具體使用可以自行百度查看。

2. 字符集

在上面的例子中,我們可以看到,正則表達式匹配完的list得到的都是一個個拆分的字符,而所謂的字符集就是匹配出來的字符集合,也就是多個字符。如下面的例子:


import re
words = "abz,acz,adz,aez,afz"
result = re.findall('a[bcd]z', words)
print(result)
>>> ['abz', 'acz', 'adz']

若想匹配到原字符串中的多個字符,我們可以用[]這樣的形式來匹配多個符合的內容,而[]中的元素相互之間是的關係。a,z來限定邊界, [bcd] 則是匹配a,z中間符合的bcd的元素,所以最終得到的結果如上。


import re
words = "abz,acz,adz,aez,afz"
result = re.findall('a[^bcd]z', words)
print(result)
>>> ['aez', 'afz']

若在字符集的正則規定前,加上^則是代表取反的意思,可以看到結果,不匹配bcd,最終結果得到的是e,f。

當然還有一種寫法是下面這樣:


import re
words = "abz,acz,adz,aez,afz"
result = re.findall('a[b-e]z', words)
print(result)
>>> ['abz', 'acz', 'adz', 'aez']

用 - 也可以來表示一個範圍,比如A-Z,a-z,0-9等....

3. 數量詞


import re
words = "I am learning Pythonnnnnn, that 's awesome!"
result = re.findall('[a-z]{4}', words)
print(result)
>>> ['lear', 'ning', 'ytho', 'nnnn', 'that', 'awes']

在字符集的基礎上,我們如果想限定多少長度的字符,可以通過{}來限定匹配字符集的長度,當我寫入4的時候,可以看到從左到右,只有當相鄰字符組成的長度為4時,才會被匹配到。

然而這樣匹配是沒有實際意義的,我現在需要的是將每個詞語拆分並且匹配到,於是有了下面的寫法:


import re
words = "I am learning Pythonnnnnn, that 's awesome!"
result = re.findall('[a-zA-Z]{1,11}', words)
print(result)
>>> ['I', 'am', 'learning', 'Pythonnnnnn', 'that', 's', 'awesome']

{最短匹配長度,最長匹配長度},在配合上字符集的正則寫法,既可拆分出原有的單詞,注意的是[a-zA-Z] 這裡用到了組合的寫法,匹配字符是符合大小寫a-z的。

大家有沒有注意到一個點,就是在數量詞這裡,我對原字符串進行正則匹配,取得長度是1~11位,那麼在am時候就已經符合一位長度了,即字母a,為什麼沒有被單獨匹配出來作為結果呢?這裡就涉及到下面要說的正則表達式的貪婪模式與非貪婪模式了。

正則表達式的貪婪與非貪婪模式

貪婪模式:意如其名,貪婪嘛,就是要多多多!多匹配既是王道!

非貪婪模式:與貪婪模式相反唄,即少匹配就是王道!

對應上面的數量詞案例時,數量詞若是採用範圍取長度時,則是默認使用貪婪模式,即多多匹配,所以才會看到能匹配到字符集長度多的單詞。而Python默認傾向於是貪婪模式的!

1. “?” 匹配0次或者1次

在實際的應用中,我們也會遇到非貪婪的情況,即少匹配,那麼如何書寫呢?


import re
words = "I am learning Pythonnnnnn, that 's awesome!"
result = re.findall('[a-zA-Z]{1,11}?', words)
print(result)
>>> ['I', 'a', 'm', 'l', 'e', 'a', 'r', 'n', 'i', 'n', 'g', 'P', 'y', 't', 'h', 'o', 'n', 'n', 'n', 'n', 'n', 'n', 't', 'h', 'a', 't', 's', 'a', 'w', 'e', 's', 'o', 'm', 'e']

只需要在數量詞後面加一個?即可。代表的是匹配前面的數量詞0次或者1次。

特殊的小技巧:?一般可以來去掉字符後面的重複項,例如原字符串:"Pythonnnnn",可以用 'Python?' 得到Python, 這點自己可以思考並實驗下。

2. “*” 匹配0次或者無限次

下面這段代碼,你認為會打印出什麼樣的結果呢?


import re
words = "I am learning Pytho,Python,Pythonnnnnn, that 's awesome!"
result = re.findall('Pytho*', words)
print(result)

輸出結果:


>>> ['Pytho', 'Pytho', 'Pytho']

因為在原字符串中匹配到o,後面就截止了。

若是這樣呢:


import re
words = "I am learning Pytho,Python,Pythonnnnnn, that 's awesome!"
result = re.findall('Python*', words)
print(result)
#輸出結果
>>> ['Pytho', 'Python', 'Pythonnnnnn']

匹配 * 號的前一個字符無限次,所以有多少n,就會被匹配到多少n。為什麼Pytho也能被匹配到呢?因為 * 號代表的是前面的字符匹配到0次也是可以的!所以pytho也會被匹配到,這裡需要注意。

3. “+” 匹配1次或者無限次


import re
words = "I am learning Pytho,Python,Pythonnnnnn, that 's awesome!"
result = re.findall('Python+', words)
print(result)
# 輸出結果
>>> ['Python', 'Pythonnnnnn']

+號是匹配前面的字符至少一次,或者n次。所以不會匹配到Pytho!

4. “.” 匹配除換行符\\n之外的其他所有字符


import re
words = "Python \\n !@#%%$*&(%)"
result = re.findall('.', words)
print(result)
>>> ['P', 'y', 't', 'h', 'o', 'n', ' ', ' ', '!', '@', '#', '%', '%', '$', '*', '&', '(', '%', ')']

可以看到,除了\\n以外的字符都匹配到了,包括空格以及其他奇怪的字符~

正則表達式組的概念

在說組之前,再來介紹一個正則的用法:

^: 匹配原字符串的首位置開始

$: 匹配原字符串的尾位置結束

如下事例:


import re
words = "110120119999"
result = re.findall('^\\d{1,9}$', words)
print(result)
>>> []

因為^和$限定了原始字符串的頭和尾,從原始字符串中匹配1~9位長度的數字,並且是從頭到尾的去匹配,並沒有長度為9的數字,所以匹配出來是空的。

正則表達式組的概念:還記得之前python的基礎數據類型元組嗎?正則中的組,與字符集恰好相反,字符集中匹配的字符之間是或的關係,而組中匹配的字符之間則是與的關係。

場景如下,我現在想匹配整個hungry!!而若是通過字符匹配的話方法:


import re
words = "I'm hungry!!hungry!!hungry!!...."
result = re.findall('hungry!!{3}', words)
print(result)
>>> []

可以看到,什麼也沒匹配到,因為現在寫的意思是匹配前面是hungry!!且最後一個歎號長度為3個,也就是說如果字符串中有hungry!!!!,即可匹配到。

python小課堂23 - 正則表達式(一)

如果想匹配到整個hungry!!並且連續的單詞出現3次,就要這麼寫啦:


import re
words = "I'm hungry!!hungry!!hungry!!!!...."
result = re.findall('(hungry!!){3}', words)
print(result)
>>> ['hungry!!']

用小括號將整個單詞括起來,它就是所謂的分組了。若我要是將{3}改成{4},就會發現,匹配不到這個結果了,因為需要組內連續出現4次才可以匹配到。如下:

"

前言

今天來介紹一下Python的正則表達式。先來看下定義,何為正則表達式?

正則表達式是一個特殊的字符序列,一個字符串是否與我們給定的這個字符序列相匹配。正則最重要的功能就是處理字符串,例如檢索你在某一段字符串中的特定單詞,或者將原來某個位置的特定字符換成你想要的字符。而對於爬蟲來說,正則表達式是必不可少的技能之一,要想正確提取源代碼中你想要的信息內容,一般來說都會用到正則。

Python的re模塊初體驗

這裡用例子來假設一個場景吧...現在你正打算轉行踏入程序員的領域,然而面臨的第一個問題就是選擇一個主修語言來作為你轉行後的學習動力。於是有個字符串language="Java,Python,Go,Js,C,C++,PHP",你下定決心要學Python,於是讓你判斷Python這門語言是否在這個字符串中存在!你會怎麼做呢?

方案一:

通過python內置函數string.index('Python')


language = 'Java,Python,Go,Js,C,C++,PHP'
print(language.index('Python'))
>>> 5

結果說明在索引下標第5位開始,尋找到了Python字符串。

方案二:

通過in關鍵詞


language = 'Java,Python,Go,Js,C,C++,PHP'
print('Python' in language)
>>> True

結果說明Python字符串存在於language中。

方案三:

通過re模塊,需要import re。


import re
language = 'Java,Python,Go,Js,C,C++,PHP'
"""
re.findall(pattern, string, flags=0):
必填的兩個參數:
第一個參數是正則表達式的模式;
第二個參數是原字符串
選填參數: flags ,傳入例如忽略大小寫的官方參數
返回的結果是: list
"""
result = re.findall('Python',language)
print(result)
>>> ['Python']

大家可以仔細看下代碼,註釋已經寫得很清楚啦....使用re.findall,見名知意,是查找到所有匹配到的,所以返回的肯定是list。不信的話,我們將代碼修改一下,在language裡多加一個Python,看下結果如何:

python小課堂23 - 正則表達式(一)

Python正則表達式的原理性概念

這個標題起的名字有些拗口,因為我找不到好的概括詞語了,現在就來解釋一下吧....我們通過re模塊來判斷了一個字符串包含不包含與原始字符串,實際上這種用法是沒有意義的,真正的正則表達式用法場景,應該是依賴於規則!

1.普通字符和元字符

還是舉例說明,還是上邊找工作的那堆語言,假設每門語言的分割,我不用逗號進行分割了,我將各種公共電話號碼隨機插入來代替逗號,於是得到language="Java110Python120Go119Js4399C999C++666PHP"。

需求變更了,現在讓你提取出電話號碼!如何去做呢?


import re
language="Java110Python120Go119Js4399C999C++666PHP"
"""
re.findall(pattern, string, flags=0):
必填的兩個參數:
第一個參數是正則表達式的模式;
第二個參數是原字符串
選填參數: flags,傳入例如忽略大小寫的官方參數
返回的結果是: list
"""
result = re.findall('\\d',language)
print(result)
>>> ['1', '1', '0', '1', '2', '0', '1', '1', '9', '4', '3', '9', '9', '9', '9', '9', '6', '6', '6']

由於每個數字都不近相同,你可以用一堆數字去寫,但是比較麻煩。若換成字符,難不成還寫滿了你要匹配的字符嗎?所以這裡提出兩個概念:普通字符和元字符。

普通字符:re.findall('Python',language)中的'Python',就是普通字符。 元字符:re.findall('\\d',language)中的'\\d',就是元字符。

所謂的普通字符,就是你寫死了的固定字符,而元字符則不一樣,它代表的是一類的字符,而我現在寫的'\\d'的含義就是匹配所有數字。需要注意的是,普通字符和元字符是在正則表達式中可以混合使用的!

而我這裡不會詳細的介紹每個元字符的用法,重要的是自己查閱相關文檔的方法,而非死記硬背這些元字符的含義,可以用到的時候再去查即可。這裡給出相關圖吧,有興趣的可以看下:

python小課堂23 - 正則表達式(一)

python小課堂23 - 正則表達式(一)

以上圖片原址: https://baike.baidu.com/item/正則表達式/1700215?fr=aladdin#3

具體使用可以自行百度查看。

2. 字符集

在上面的例子中,我們可以看到,正則表達式匹配完的list得到的都是一個個拆分的字符,而所謂的字符集就是匹配出來的字符集合,也就是多個字符。如下面的例子:


import re
words = "abz,acz,adz,aez,afz"
result = re.findall('a[bcd]z', words)
print(result)
>>> ['abz', 'acz', 'adz']

若想匹配到原字符串中的多個字符,我們可以用[]這樣的形式來匹配多個符合的內容,而[]中的元素相互之間是的關係。a,z來限定邊界, [bcd] 則是匹配a,z中間符合的bcd的元素,所以最終得到的結果如上。


import re
words = "abz,acz,adz,aez,afz"
result = re.findall('a[^bcd]z', words)
print(result)
>>> ['aez', 'afz']

若在字符集的正則規定前,加上^則是代表取反的意思,可以看到結果,不匹配bcd,最終結果得到的是e,f。

當然還有一種寫法是下面這樣:


import re
words = "abz,acz,adz,aez,afz"
result = re.findall('a[b-e]z', words)
print(result)
>>> ['abz', 'acz', 'adz', 'aez']

用 - 也可以來表示一個範圍,比如A-Z,a-z,0-9等....

3. 數量詞


import re
words = "I am learning Pythonnnnnn, that 's awesome!"
result = re.findall('[a-z]{4}', words)
print(result)
>>> ['lear', 'ning', 'ytho', 'nnnn', 'that', 'awes']

在字符集的基礎上,我們如果想限定多少長度的字符,可以通過{}來限定匹配字符集的長度,當我寫入4的時候,可以看到從左到右,只有當相鄰字符組成的長度為4時,才會被匹配到。

然而這樣匹配是沒有實際意義的,我現在需要的是將每個詞語拆分並且匹配到,於是有了下面的寫法:


import re
words = "I am learning Pythonnnnnn, that 's awesome!"
result = re.findall('[a-zA-Z]{1,11}', words)
print(result)
>>> ['I', 'am', 'learning', 'Pythonnnnnn', 'that', 's', 'awesome']

{最短匹配長度,最長匹配長度},在配合上字符集的正則寫法,既可拆分出原有的單詞,注意的是[a-zA-Z] 這裡用到了組合的寫法,匹配字符是符合大小寫a-z的。

大家有沒有注意到一個點,就是在數量詞這裡,我對原字符串進行正則匹配,取得長度是1~11位,那麼在am時候就已經符合一位長度了,即字母a,為什麼沒有被單獨匹配出來作為結果呢?這裡就涉及到下面要說的正則表達式的貪婪模式與非貪婪模式了。

正則表達式的貪婪與非貪婪模式

貪婪模式:意如其名,貪婪嘛,就是要多多多!多匹配既是王道!

非貪婪模式:與貪婪模式相反唄,即少匹配就是王道!

對應上面的數量詞案例時,數量詞若是採用範圍取長度時,則是默認使用貪婪模式,即多多匹配,所以才會看到能匹配到字符集長度多的單詞。而Python默認傾向於是貪婪模式的!

1. “?” 匹配0次或者1次

在實際的應用中,我們也會遇到非貪婪的情況,即少匹配,那麼如何書寫呢?


import re
words = "I am learning Pythonnnnnn, that 's awesome!"
result = re.findall('[a-zA-Z]{1,11}?', words)
print(result)
>>> ['I', 'a', 'm', 'l', 'e', 'a', 'r', 'n', 'i', 'n', 'g', 'P', 'y', 't', 'h', 'o', 'n', 'n', 'n', 'n', 'n', 'n', 't', 'h', 'a', 't', 's', 'a', 'w', 'e', 's', 'o', 'm', 'e']

只需要在數量詞後面加一個?即可。代表的是匹配前面的數量詞0次或者1次。

特殊的小技巧:?一般可以來去掉字符後面的重複項,例如原字符串:"Pythonnnnn",可以用 'Python?' 得到Python, 這點自己可以思考並實驗下。

2. “*” 匹配0次或者無限次

下面這段代碼,你認為會打印出什麼樣的結果呢?


import re
words = "I am learning Pytho,Python,Pythonnnnnn, that 's awesome!"
result = re.findall('Pytho*', words)
print(result)

輸出結果:


>>> ['Pytho', 'Pytho', 'Pytho']

因為在原字符串中匹配到o,後面就截止了。

若是這樣呢:


import re
words = "I am learning Pytho,Python,Pythonnnnnn, that 's awesome!"
result = re.findall('Python*', words)
print(result)
#輸出結果
>>> ['Pytho', 'Python', 'Pythonnnnnn']

匹配 * 號的前一個字符無限次,所以有多少n,就會被匹配到多少n。為什麼Pytho也能被匹配到呢?因為 * 號代表的是前面的字符匹配到0次也是可以的!所以pytho也會被匹配到,這裡需要注意。

3. “+” 匹配1次或者無限次


import re
words = "I am learning Pytho,Python,Pythonnnnnn, that 's awesome!"
result = re.findall('Python+', words)
print(result)
# 輸出結果
>>> ['Python', 'Pythonnnnnn']

+號是匹配前面的字符至少一次,或者n次。所以不會匹配到Pytho!

4. “.” 匹配除換行符\\n之外的其他所有字符


import re
words = "Python \\n !@#%%$*&(%)"
result = re.findall('.', words)
print(result)
>>> ['P', 'y', 't', 'h', 'o', 'n', ' ', ' ', '!', '@', '#', '%', '%', '$', '*', '&', '(', '%', ')']

可以看到,除了\\n以外的字符都匹配到了,包括空格以及其他奇怪的字符~

正則表達式組的概念

在說組之前,再來介紹一個正則的用法:

^: 匹配原字符串的首位置開始

$: 匹配原字符串的尾位置結束

如下事例:


import re
words = "110120119999"
result = re.findall('^\\d{1,9}$', words)
print(result)
>>> []

因為^和$限定了原始字符串的頭和尾,從原始字符串中匹配1~9位長度的數字,並且是從頭到尾的去匹配,並沒有長度為9的數字,所以匹配出來是空的。

正則表達式組的概念:還記得之前python的基礎數據類型元組嗎?正則中的組,與字符集恰好相反,字符集中匹配的字符之間是或的關係,而組中匹配的字符之間則是與的關係。

場景如下,我現在想匹配整個hungry!!而若是通過字符匹配的話方法:


import re
words = "I'm hungry!!hungry!!hungry!!...."
result = re.findall('hungry!!{3}', words)
print(result)
>>> []

可以看到,什麼也沒匹配到,因為現在寫的意思是匹配前面是hungry!!且最後一個歎號長度為3個,也就是說如果字符串中有hungry!!!!,即可匹配到。

python小課堂23 - 正則表達式(一)

如果想匹配到整個hungry!!並且連續的單詞出現3次,就要這麼寫啦:


import re
words = "I'm hungry!!hungry!!hungry!!!!...."
result = re.findall('(hungry!!){3}', words)
print(result)
>>> ['hungry!!']

用小括號將整個單詞括起來,它就是所謂的分組了。若我要是將{3}改成{4},就會發現,匹配不到這個結果了,因為需要組內連續出現4次才可以匹配到。如下:

python小課堂23 - 正則表達式(一)

總結

今天主要介紹了python的re模塊的findall方法,此方法是入門正則表達式一個比較好的學習方式,通過各種實例可以看到最終匹配到的結果,而需要注意的點是:普通字符和元字符,元字符相當於是系統的寫法,每種寫法代表不同的含義,在使用的時候可以將二者混合使用來達到你最終想匹配的值,現在也許看著正則還會有很多的疑惑,後續寫到爬蟲的時候,一講就明白了!

至此完!

有想交流溝通python相關知識的同學,歡迎關注公號: migezatan.(咪哥雜談)

"

相關推薦

推薦中...