微信公眾號:碼農充電站pro
個人主頁:https://codeshellme.github.io
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:掃描整個字符串,返回所有的匹配項,返回結果是一個字符串列表
(完。)
歡迎關注作者公眾號,獲取更過技術干貨。