Regex 正規表示式入門

碼農充電站發表於2020-05-04

在這裡插入圖片描述


0,什麼是正規表示式

正規表示式Regular Expression簡寫為Regex),又稱為規則表示式,它是一種強大的文字匹配模式,其用於在字串中查詢匹配符合特定規則的子串。

正規表示式是獨立於程式語言而存在的,它並不依賴於某種程式語言。只要一種程式語言實現了正規表示式引擎,那麼這種程式語言,就具備了正規表示式模式匹配的功能。每種工具程式語言對正規表示式的實現,雖有細節上的不同,但基本的使用是相同的。

正規表示式的基本工作原理如下:

在這裡插入圖片描述

1,正規表示式的由來

1956 年,美國數學家Stephen Kleene 在兩位神經生理學家(Warren McCullochWalter Pitts)的早期工作的基礎上,發表了一篇標題為神經網事件的表示法的論文,由此引入了正規表示式的概念。

之後,Unix 之父Ken Thompson把這一成果應用於計算搜尋演算法的一些早期研究。隨後,他將這一符號系統應用於Unix 系統中的 qed 編輯器,這是正規表示式的第一個實用程式。

此後,正規表示式被廣泛的應用於類Unix 系統的工具中,如 grepperl 等。

2,正規表示式工具

RegexBuddy 是一個很不錯的軟體。

Regexr 是一個線上工具。

3,正規表示式語法

正規表示式由一些普通字元(比如英文字母,數字)和元字元(代表特定含義)組成。

正規表示式作為一個字元模板,在字串中匹配一個或多個符合特定規則的子串。

3.1,元字元

元字元就是包含特定含義的字元。如果想匹配這些元字元,需要使用轉義字元\ 進行轉義。

下表是一些常用的元字元:

字元 含義
\ 轉義字元,常用於轉義元字元
. 匹配除換行符\n 之外的任何單字元
$ 匹配字串的結尾位置
^ 匹配字串的開始位置。當寫在中括號[]內時,表示不匹配該中括號中的字符集合
[^xy] 匹配非x非y字元
() 被小括號包含的多個字元,將作為一整個字元
(pattern) 寫在小括號()內的表示式,表示一個分組,用於提取內容
(?:pattern) 只表示一個分組,不提取內容
[] 被中括號包含的多個字元,這多個字元的關係是邏輯或的關係
[xyz] 字符集合,匹配xyz
[0-9] 匹配09之間的數字
[a-z] 匹配az之間的字元
[^a-z] 匹配不在az範圍內的任意字元
| 寫在兩個字元之間,代表邏輯或的關係
x|y 匹配xy
\b 匹配一個單詞邊界
\B 匹配非單詞邊界
\d 匹配一個數字字元,等價於[0-9]
\D 匹配一個非數字字元,等價於[^0-9]
\s 匹配任何空白字元,包括空格製表符
\S 匹配任何非空白字元
\w 匹配字母數字下劃線,等價於[A-Za-z0-9_]
\W 匹配非字母非數字非下劃線,等價於[^A-Za-z0-9_]
\f 匹配換頁符
\n 匹配換行符
\r 匹配回車符
\t 匹配製表符
\v 匹配垂直製表符

3.2,限定符

限定符也屬於元字元,用來限定一個子表示式出現的次數。

字元 含義
* 匹配前面的子表示式零次多次
+ 匹配前面的子表示式一次多次
? 匹配前面的子表示式零次一次
{n} 匹配前面的子表示式n次
{n,} 匹配前面的子表示式至少n次
{n,m} 匹配前面的子表示式n 到m 次

4,正規表示式示例

我們逐個介紹一下每種元字元的使用方式,下面的例子我們都使用RegexBuddy 軟體來演示。

4.1,轉義字元\

轉義字元用來對一些元字元進行轉義,使這些元字元失去其特定的含義,只表示一個普通的字元。

比如我們想匹配字串aaa^bbb 中的a^b 子串,我們需要用模式a\^b 來匹配,^ 之前需要加一個轉義字元\


在這裡插入圖片描述


4.2,元字元.

元字元. 可匹配任意(除了換行符\n)的單字元,意思就是. 可以代表任意(除了換行符\n)的單字元。


在這裡插入圖片描述


4.3,開始位置^與結束位置$

符號^ 表示匹配的子串在行首,符號$ 表示匹配的子串在行尾


匹配行首

在這裡插入圖片描述


匹配行尾

在這裡插入圖片描述


行首行尾

在這裡插入圖片描述

4.4,邏輯或|

符號| 寫在兩個子表示式之間表示邏輯或的意思。

例如模式串ab|cd,匹配abcd


在這裡插入圖片描述


4.5,限定符

限定符用於限定一個子表示式出現的次數,一共6 種,這裡給出一些示例。

符號*

模式串ab*c,表示字元ac 之間需要出現0 次多次字元b


在這裡插入圖片描述


符號+

模式串ab+c,表示字元ac 之間需要出現1 次多次字元b,即至少出現1次字元b


在這裡插入圖片描述


符號?

模式串ab?c,表示字元ac 之間需要出現0 次1次字元b


在這裡插入圖片描述


符號{n}{n,}{n,m}

  • ab{3}c:符號b 出現的次數必須是3
  • ab{3,}c:符號b 出現的次數必須大於等於3
  • ab{3,5}c:符號b 出現的次數必須在35 之間,包括35

在這裡插入圖片描述


4.6,字元簇[]

寫在中括號[] 內的多個字元代表邏輯或的意思。

模式串a[bef]c,表示ac中間的字元必須是bef


在這裡插入圖片描述


當符號^ 寫在中括號[] 內時,表示邏輯非的意思。

模式串a[^bef]c,表示ac中間的字元不能是bef


在這裡插入圖片描述


符號- 寫在中括號[],表示範圍的意思:

示例 含義
[a-z] 表示az 之間的任意字元
[A-Z] 表示AZ 之間的任意字元
[0-9] 表示09 之間的任意數字,含義同\d
[^0-9] 表示任意非數字,含義同\D
[A-Za-z0-9_] 表示任意字母數字下劃線 ,含義同\w
[^A-Za-z0-9_] 表示任意非字母非數字非下劃線 ,含義同\W
[ \f\r\t\n] 表示任意的空白字元,含義同\s
[^ \f\r\t\n] 表示任意的非空白字元,含義同\S

4.7,字元組合()

寫在小括號()中的多個字元,會被看成一個整體。


在這裡插入圖片描述


4.8,單詞邊界\b\B

符號\b 是指一個單詞邊界,比如空白字元和標點符號等。
符號\B 表示非單詞邊界


在這裡插入圖片描述


5,貪婪與非貪婪模式

正規表示式中貪婪的意思就是貪多,意思就是正則在匹配的過程中,總是去匹配儘可能多的字元,符號? 可以將貪婪轉換為非貪婪


在這裡插入圖片描述


6,在Python 中使用正則

Python 中提供了re 模組,用於支援正規表示式功能。

python 中一般在表示式前加r,表示原始字元,不用考慮轉義的問題。例如r'abc'

下面開啟python 終端:

  • 首先引入模組,import re
  • help(re) 可檢視re 模組幫助手冊
  • dir(re) 可檢視其支援的屬性和方法
>>> python		`開啟python 終端`
_____________________________________________
Python 2.7.17 (default, Nov  7 2019, 10:07:09) 
[GCC 7.4.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.

>>> import re   # 引入re 模組
>>> 
>>> help(re)	# 檢視幫助手冊
>>>
>>> dir(re)		# 檢視re 支援的屬性和方法

6.1,re 模組常用方法

方法 含義
match 用於匹配表示式
search 查詢匹配項
findall 查詢所有的匹配項
compile 編譯正規表示式

詳細解釋:

match(pattern, string, flags=0)
        Try to apply the pattern at the start of the string, returning
        a match object, or None if no match was found.

search(pattern, string, flags=0)
        Scan through string looking for a match to the pattern, returning
        a match object, or None if no match was found.
        
findall(pattern, string, flags=0)
        Return a list of all non-overlapping matches in the string.
        
        If one or more groups are present in the pattern, return a
        list of groups; this will be a list of tuples if the pattern
        has more than one group.
        
        Empty matches are included in the result.

compile(pattern, flags=0)
        Compile a regular expression pattern, returning a pattern object.

可以看到,每個方法中都有一個flag 引數,它表示匹配模式,預設值為0,表示普通模式。

flag 引數的值有以下幾種選擇,可以使用符號| 連線多種選擇:

`I/IGNORECASE`  Perform case-insensitive matching.
`L/LOCALE`      Make \w, \W, \b, \B, dependent on the current locale.
`M/MULTILINE`   "^" matches the beginning of lines (after a newline)
                as well as the string.
                "$" matches the end of lines (before a newline) as well
                as the end of the string.
`S/DOTALL`      "." matches any character at all, including the newline.
`X/VERBOSE`     Ignore whitespace and comments for nicer looking RE's.
`U/UNICODE`     Make \w, \W, \b, \B, dependent on the Unicode locale.

6.2,match 方法

re.match 嘗試從字串的起始位置開始匹配:

  • 成功:返回SRE_Match 物件
  • 失敗:返回None
>>> m = re.match(r'abc', 'abcde')
>>> print m  # 匹配成功
<_sre.SRE_Match object at 0x7f91544cff80>	
>>> 
>>> 
>>> m = re.match(r'abc', 'fabcde')
>>> print m  # `fabcde` 不是以`abc` 開頭,匹配失敗                  
None                     
>>>

6.3,search 方法

re.search 掃描整個字串,直到找到第一個成功的匹配:

  • 成功:返回SRE_Match 物件
  • 失敗:返回None
>>> m = re.search(r'abc', 'abcde')
>>> print m  # 匹配成功
<_sre.SRE_Match object at 0x7f91544cff80>
>>>
>>> m = re.search(r'abc', 'fabcde')
>>> print m # 匹配成功
<_sre.SRE_Match object at 0x7f9154521b90>

6.4,findall 方法

re.findall 在字串中查詢所有匹配的子串:

  • 成功:返回一個列表
  • 失敗:返回空列表[]
>>> re.findall(r'abc', 'fabcdeabc')
['abc', 'abc']		# 找到兩個`abc` 子串
>>> 
>>> re.findall(r'abce', 'fabcdeabc')
[]                  # 沒找到子串
>>> 

6.5,compile 方法

在使用正則時,re 模組會先將正規表示式進行編譯,然後才會去字串中匹配。

如果一個正規表示式會使用很多次,我們可以使用re.compile 方法對錶達式進行預編譯,這樣就不會在每次用到這個表示式時都進行編譯,有助於提高效率。

該方法返回一個SRE_Pattern 物件,該物件又包含matchsearchfindall 等方法,使用方法如下:

>>> reg =  re.compile(r'abc')      # 編譯
>>> 
>>> type(reg)
<type '_sre.SRE_Pattern'>
>>>
>>> reg.findall('fabcdeabc')      # 找到兩個
['abc', 'abc']  
>>> 
>>> reg.match('fabcdeabc')        # 沒有匹配上
>>> 
>>> reg.search('fabcdeabc')       # 匹配上
<_sre.SRE_Match object at 0x7f9154521b90>

6.6,SRE_Match 物件

SRE_Match 物件用於獲取分組,寫在小括號()內的表示式是一個分組。

>>> # 正則中包含兩個分組
>>> m = re.match(r'(\d*)-(\w*)', '123-abc-')
>>> m
<_sre.SRE_Match object at 0x7f91544e0ae0>
>>> m.group(0) # 獲取整個匹配的串,同 m.group()
'123-abc'
>>> m.group(1) # 獲取第一個分組
'123'
>>> m.group(2) # 獲取第二個分組
'abc'
>>>

6.7,match,search,findall 比較

我們來看下matchsearchfindall 三個方法的異同點:

  • match:必須從字串的開頭匹配,只會有一個匹配項,返回結果是SRE_Match 物件
  • search:掃描整個字串,直到匹配到第一個為止,只會有一個匹配項,返回結果是SRE_Match 物件
  • findall:掃描整個字串,返回所有的匹配項,返回結果是一個字串列表

(完。)

相關文章