0,什麼是正規表示式
正規表示式
(Regular Expression
簡寫為Regex
),又稱為規則表示式
,它是一種強大的文字匹配模式,其用於在字串中查詢匹配
符合特定規則的子串。
正規表示式是獨立於程式語言
而存在的,它並不依賴於某種程式語言。只要一種程式語言實現了正規表示式引擎
,那麼這種程式語言,就具備了正規表示式模式匹配的功能。每種工具
或程式語言
對正規表示式的實現,雖有細節上的不同,但基本的使用是相同的。
正規表示式的基本工作原理如下:
1,正規表示式的由來
1956 年,美國數學家Stephen Kleene
在兩位神經生理學家(Warren McCulloch
和 Walter Pitts
)的早期工作的基礎上,發表了一篇標題為神經網事件的表示法
的論文,由此引入了正規表示式的概念。
之後,Unix 之父Ken Thompson
把這一成果應用於計算搜尋演算法
的一些早期研究。隨後,他將這一符號系統應用於Unix 系統
中的 qed 編輯器
,這是正規表示式的第一個實用程式。
此後,正規表示式被廣泛的應用於類Unix 系統的工具中,如 grep
,perl
等。
2,正規表示式工具
RegexBuddy 是一個很不錯的軟體。
Regexr 是一個線上工具。
3,正規表示式語法
正規表示式由一些普通字元
(比如英文字母,數字)和元字元
(代表特定含義)組成。
正規表示式作為一個字元模板,在字串中匹配一個或多個符合特定規則的子串。
3.1,元字元
元字元
就是包含特定含義的字元。如果想匹配這些元字元
,需要使用轉義字元\
進行轉義。
下表是一些常用的元字元:
字元 | 含義 |
---|---|
\ |
轉義字元,常用於轉義元字元 |
. |
匹配除換行符\n 之外的任何單字元 |
$ |
匹配字串的結尾位置 |
^ |
匹配字串的開始位置 。當寫在中括號[] 內時,表示不匹配該中括號 中的字符集合 |
[^xy] |
匹配非x ,非y 字元 |
() |
被小括號包含的多個字元,將作為一整個字元 |
(pattern) |
寫在小括號() 內的表示式,表示一個分組 ,用於提取內容 |
(?:pattern) |
只表示一個分組 ,不提取內容 |
[] |
被中括號包含的多個字元,這多個字元的關係是邏輯或 的關係 |
[xyz] |
字符集合,匹配x 或y 或z |
[0-9] |
匹配0 到9 之間的數字 |
[a-z] |
匹配a 到z 之間的字元 |
[^a-z] |
匹配不在a 到z 範圍內的任意字元 |
| |
寫在兩個字元之間,代表邏輯或 的關係 |
x|y |
匹配x 或 y |
\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
,匹配ab
或 cd
。
4.5,限定符
限定符
用於限定一個子表示式
出現的次數
,一共6 種,這裡給出一些示例。
符號*
模式串ab*c
,表示字元a
和c
之間需要出現0 次
或多次
字元b
。
符號+
模式串ab+c
,表示字元a
和c
之間需要出現1 次
或多次
字元b
,即至少出現1次
字元b
。
符號?
模式串ab?c
,表示字元a
和c
之間需要出現0 次
或1次
字元b
。
符號{n}
和{n,}
和{n,m}
ab{3}c
:符號b 出現的次數必須是3
ab{3,}c
:符號b 出現的次數必須大於等於3
ab{3,5}c
:符號b 出現的次數必須在3
和5
之間,包括3
和5
4.6,字元簇[]
寫在中括號[]
內的多個字元代表邏輯或
的意思。
模式串a[bef]c
,表示a
和c
中間的字元必須是b
或e
或f
。
當符號^
寫在中括號[]
內時,表示邏輯非
的意思。
模式串a[^bef]c
,表示a
和c
中間的字元不能是b
或e
或f
。
符號-
寫在中括號[]
,表示範圍
的意思:
示例 | 含義 |
---|---|
[a-z] |
表示a 到z 之間的任意字元 |
[A-Z] |
表示A 到Z 之間的任意字元 |
[0-9] |
表示0 到9 之間的任意數字,含義同\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
物件,該物件又包含match
,search
,findall
等方法,使用方法如下:
>>> 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 比較
我們來看下match
,search
,findall
三個方法的異同點:
- match:必須從字串的開頭匹配,只會有一個匹配項,返回結果是
SRE_Match
物件 - search:掃描整個字串,直到匹配到第一個為止,只會有一個匹配項,返回結果是
SRE_Match
物件 - findall:掃描整個字串,返回所有的匹配項,返回結果是一個字串列表
(完。)