正則表達式入門和Python中的使用

個人博客文章:Python 中的正則表達式

前言

正則表達式很重要,特別是對於字符串的處理。作爲一個使用 Python 的人不會使用正則表達式的使用,到底浪費了多少時間在處理字符,天才知道啊,鑑於自己的心酸歷程,決定還是好好做做筆記,但還需要多加練習,學以致用。

正則表達式

什麼是正則表達式?

正則表達式,即 regular expression,通常簡寫爲 regex 或者 regexp, 簡單的來說就是用於查找目標文本中的特定字符串,這些特定字符串遵循正則表達式所描述的規則。因此正則表達式就是用來定義字符串組成的規則的,然後通過函數實現對規則的解釋,查找特定的字符串。

應用場景

  • 提取字符串,找出符合規則的字符串,如查找文本中的形如 [email protected] 的郵箱
  • 替換字符串
  • 網頁信息填寫時,驗證用戶名、郵箱等是否符合網站設定的規則

基本語法一覽

以下正則表達式,可以查找到諸如 hello-regexregex101_cool110_119等字符串,這些字符串以字母 a-z或數字 0-9、下劃線 _、連字符 -,開頭和結尾,長度在 3 到 15 之間。圖轉自 learn_regex.
在這裏插入圖片描述

基礎

元字符

正則表達式是用來描述字符串組成的規則的,那麼它如何描述呢,就像編程語言有關鍵字一樣,它也有描述規則的特殊字符,稱爲元字符,這些字符都用特殊的含義。

元字符 描述
. 表示一個任意字符,換行符除外
+ 表示重複 >=1 次,+之前的字符
* 表示重複 >= 0 次,*之前的字符
? 表示重複 0 或 1次,之前的字符
^ 從字符串頭部開始匹配
$ 從字符串尾部開始匹配
[] 匹配方括號內的任意字符,用來自定義字符集合
[^] 匹配除方括號以爲的任意字符,用來過濾字符集合
{m,n} 匹配 m 到 n 個 大括號之前的字符
(xyz) 完全匹配 xyz
| 或運算符,表示匹配或運算符前或者後面的字符
\ 轉義字符,用於元字符之前,去掉特殊含義

簡寫字符集

正則表達式提供一些常用的字符集簡寫. 如下:

簡寫 描述
. 除換行符外的所有字符
\w 匹配所有字母和數字字符, 等同於 [a-zA-Z0-9_]
\W 匹配所有非字母和非數字字符, 即符號, 等同於: [^\w]
\d 匹配數字: [0-9]
\D 匹配非數字: [^\d]
\s 匹配所有空格字符, 等同於: [\t\n\f\r\p{Z}]
\S 匹配所有非空格字符: [^\s]
\f 匹配一個換頁符
\n 匹配一個換行符
\r 匹配一個回車符
\t 匹配一個製表符
\v 匹配一個垂直製表符
\p 匹配 CR/LF (等同於 \r\n),用來匹配 DOS 行終止符

進階

標誌

標誌又稱爲模式修正符,它是用來改變正則表達式的搜索模式的,在不使用 標誌 時,搜索時,區分大小寫,且只匹配每行中的第一個符合規則的字符串,範圍爲一行,就是隻能行內搜索不能進行跨行搜索,那麼相應的 標誌 就有三個:

標誌 描述
i 不區分大小寫
g 行內全局搜索,匹配所有結果
m 跨行搜索

表達式內修改標誌

可以在表達式內規定字符使用特定模式。

(?im)

>>> import re
>>> regex = r'(?i)\bcat|dog'
>>> s = 'Here are cAT, cat, dog, Dog'
>>> re.findall(regex, s)
['cAT', 'cat', 'dog', 'Dog']

錨點(定位置)

錨點用於規定匹配的位置,除了 ^$可以分別指定字符串的開頭和結尾,還有以下錨點:

錨點 描述
\A 字符串頭部
\Z 字符串尾部
\b 單詞分界
\B 分單詞分界
>>> re.search(r'\bcat\b', 'The fat cat sat on the mat.') # 匹配單詞 cat
<_sre.SRE_Match object; span=(8, 11), match='cat'>
>>> re.search(r'at\B', 'The faty cat sat on the mat.') # 匹配單詞中的 at
<_sre.SRE_Match object; span=(5, 7), match='at'>

零寬度斷言(前後預查)

有時候我們需要查找有帶有前後綴的文本,但我們不需要前後綴部分,如在如下人員信息文本中提取所有國家名字

id:1
Name:Jack
Country:US
id:2
Name:Rose
Country:UK
...

這時候就可以使用 零寬度斷言。零寬度斷言就是要查找的特定字符的前後綴規則,但這些前後綴只用於約束查找,實際結果不包含這些前後綴,這大概就是爲什麼稱作零寬度(個人理解)。

零寬度斷言有四種:

符合 描述
(?=chars) 正先行斷言,表示必須有特定後綴 chars
(?!chars) 負先行斷言,表示除特定後綴 chars 以外的所有後綴均可
(?<=chars) 正後發斷言,表示必須有特定前綴 chars
(?<!chars) 負後發斷言,表示除了特定前綴 chars 外的所有前綴均可

從上面的人員信息文本中查找所有國家名可以使用正後發斷言,表示國家名前面必須有前綴 Country:

/(?<=(Country:))\w*/gm,這裏用到了標誌gm 分別表示,在一行內匹配所有符合的,以及在多行匹配

分組

使用正則表達式還可以從字符串中提取子字符串,正則表達式使用 () 成組匹配,我們可以通過定義多個組抽取字符串中的多個子字符串, 如提取郵箱地址的用戶名(@之前)和郵箱的域名(@之後),我們可以使用 ^([0-9a-zA-Z]\w*)@(\w*\.com)$,提取出兩個 組。

在 Python 中, 使用 _sre.SRE_Match 對象的 group() 方法

>>> email = r'^([0-9a-zA-Z]\w*)@(\w*\.com)$'
>>> pemail = re.compile(email)
>>> m = pemail.match('[email protected]') # 匹配成功就會返回一個 _sre.SRE_Match 對象
>>> m.group(1)
'xman'
>>> m = pemail.match('[email protected]') 
>>> m # 匹配不成功,返回 None
>>> pemail.findall('[email protected]')
[('xman', 'outlook.com')]

其實 零寬度斷言 也算是 分組的一種,只不過分組只是用來約束而已。如果不想成組返回但還是需要,成組匹配,如 findall函數,如果存在分組,則會匹配的分組結果,這時可以使用:

(?:)

進行分組匹配,但是結果是沒有分組的

>>> re.findall('^(?:\w+)@(?:\w*\.com)$', '[email protected]')		     
['[email protected]']

貪婪匹配和惰性匹配

使用正則表達式進行文本匹配時,默認使用貪婪匹配模式,也就是匹配儘可能長的字符串,但是很多時候我們得不到想要的結果,如我們想要在下面文本中查找類似 xxxrose的字符串

jack@rose is a comination of jack and rose using @

使用 /.*rose/,匹配到 jack@rose is a comination of jack and rose

我們需要使用惰性匹配,使用 ? 切換。

使用 /.*?rose/,匹配到 jack@rose

使用 *+? {m,n} 時都在其後添加 ?切換成惰性匹配模式。

Python + Regex

Python 中對字符串的處理有了 正則表達式的加持,可謂是如虎添翼,極大提高我們的對字符串處理的效率。要在 Python 使用正則表達式,需要使用 re模塊中的函數,通常用於進行字符查找、替換、切割等。

基本流程

使用 re 模塊進行正則表達式處理,主要有兩個步驟:

  1. 將正則表達式,編譯成 _sre.SRE_Pattern 對象,
  2. 使用對象的方法使用正則表達式進行匹配、查找、切割等操作。
>>> import re
>>> regex = r'\d{12}'  #12個連續數字
>>> p = re.compile(regex) # 編譯表達式
>>> s = 'What dose the code 110119120114 mean'
>>> regex.search(regex) # 在字符串中查找
<_sre.SRE_Match object; span=(19, 31), match='110119120114'> # 返回一個 _sre.SRE_Match 對象

由於在 Python 中也有需要轉義的字符,就會導致需要很多轉義的情況如,如果需要匹配 “\text\" 那麼就需要對需要轉義兩次,第一次轉義是因爲在正則表達式中 \ 是元字符,第二次轉義是因爲 \ 在 Python 中也需要轉義,最終的正則表達式爲 ”\\\\test\\\\",爲了避免麻煩,直接使用 Python 字符串的 r 前綴,就不需要考慮 Python 的轉義了,但是 正則表達式中的元字符仍需要轉義的,可簡寫爲 r”\\test\\

Match 對象

字符匹配後通常會以返回一個 Match 對象,匹配的結果存在 Match 對象中,主要方法有:

方法/屬性 描述
group([id=0]) 返回進行匹配的整個字符串,默認參數爲0,分組id爲1,2,,
start() 返回匹配的起始位置
end() 返回匹配的結束位置
span() 返回(start, end) ,匹配位置的 tuple
>>> regex = r'\d{11}(?=\W)' # 找 11 位的數字
>>> nums = '12213313451334,566778,13315551666,'
>>> p = re.compile(regex)
>>> p.search(nums)
<_sre.SRE_Match object; span=(3, 14), match='13313451334'>
>>> result.group()
'13313451334'
>>> result.start()
3

標誌

正則表達式中的標誌 re 模塊中的標誌
i re.I
m re.M
s,用於使得 .可以表示任意字符,包括換行符 re.S
x,用於使得 正則表達式 可以換行和添加註釋 re.X

常用的函數

re.compile(pattern, flags=0)

將一個正則表達式編譯成 正則表達式 對象,以便於重複使用,該匹配模式。

# 查找
import re
regex = re.complie(pattern)
result = regex.match(string)
# 等同於
result = re.match(pattern, string)

正則表達式的處理流程:

所有的正則表達式都需要顯示或者隱式的編譯成 正則表達式 對象,才能進一步使用正則表達式去匹配字符串,因此對於需要重複使用的模式,應該一次性進行編譯。

re.match(pattern, string, flags=0) | pattern.match(string[, pos[, endpos]])

以字符串頭部爲匹配的起點,匹配模式,如果存在匹配,返回一個 Match對象,如果不存在匹配返回 None

re.search(pattern, string, flags=0) | pattern.search(string[, pos[, endpos]])

從字符任意位置匹配模式,如果存在匹配,返回一個 Match對象,如果不存在匹配返回 None

matchsearch 區別在於,search可以在字符串的任意位置進行匹配,而 match默認從頭開始匹配。

re.match('s', 'test') # 返回 None,字符串頭部不匹配
re.match('t', 'test') # 返回 Match 對象
re.search('s', 'test') # 返回 Match 對象,在字符串中任意匹配

re.fullmatch(pattern, string, flags=0) | pattern.fullmatch(string[, pos[, endpos]])

如何整個字符串符合模式,返回一個 Match 對象,不匹配返回 None。

re.findall(pattern, string, flags=0) | pattern.findall(string[, pos[, endpos]])

返回字符串中所有匹配的子字符串,返回一個 List 對象。

起到了正則表達式中的 g標誌的作用,故 python 的 re 模塊沒有該標誌

re.finditer(pattern, string, flags=0) | pattern.finditer(string[, pos[, endpos]])

返回生成 Match 對象的迭代器。

>>> import re
>>> regex = r'\w+@\w+\.com'
>>> p = re.compile(regex)
>>> s = '[email protected],[email protected],[email protected]'
>>> res = p.finditer(s)
>>> for r in res:
	print(r[0])
#輸出	
pig@dog.com
list@tuple.com
2@111.com

re.split(pattern, string, maxsplit=0, flags=0) | pattern.split(string[, pos[, endpos]])

根據模式將字符串進行拆分。

>>> s = '123,333, 155--134-,were&here,we|--are-you' # 以非數字、非字母不包括 -,以及2個以上的 - 爲分隔符
>>> regex = r'\s|-{2,}|[^\w-]'		     
>>> re.split(regex, s)		     
['123', '333', '', '155', '134-', 'were', 'here', 'we', '', 'are-you']

參考

  1. learn-regex
  2. 廖雪峯Python教程
  3. Regular expression operations
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章