文:鄭元春
人生苦短贝乎,我用Python!
0x01:什么是正則表達(dá)式
In theoretical computer science and formal language theory, a regular expression (sometimes called a rational expression)[1][2] is a sequence of characters that define a search pattern, mainly for use in pattern matching with strings, or string matching, i.e. "find and replace"-like operations. The concept arose in the 1950s, when the American mathematician Stephen Kleene formalized the description of a regular language, and came into common use with the Unix text processing utilities ed, an editor, and grep, a filter.
--《Wiki Regular expression》
中文簡述:在理論計(jì)算科學(xué)領(lǐng)域和形式化語言理論中摊求,regular expression(有時候也叫做rational expression)是一種定義了搜索模式的特征序列署恍,主要是用于字符串的模式匹配立由,或是字符的匹配佃蚜。
熟悉Linux的同學(xué)肯定在shell中就用過各種各樣的正則表達(dá)式发魄,基本上每種語言妒貌,像是C++泰偿,Java熄守,JavaScript和Python等都是支持正則表達(dá)式的應(yīng)用。有的時候書寫起來可能會有細(xì)微的差別甜奄,并且對正則符號的支持程度也不一樣柠横。
由于近來要做些NLP之類的處理,所以就學(xué)習(xí)了下Python中的正則表達(dá)式课兄。學(xué)會使用正則表達(dá)式真的會極大的提高你的開發(fā)效率牍氛,但是正則表達(dá)式學(xué)習(xí)起來是有一定的門檻的,因?yàn)槔锩鏁砍兜揭欢ǖ哪J匠橄竽芰ρ滩啾扔谄渌膯栴}來說有點(diǎn)難度搬俊。不過,作為一個程序員蜒茄,被人稱為情商加到智商上的生物唉擂,我們不應(yīng)該就是勇往直前么。
看過一些大牛寫的正則表達(dá)式檀葛,真的是既簡潔又很優(yōu)雅玩祟。并且很神奇的能夠處理那些看似復(fù)雜的文本解析任務(wù)。我的個人理解是正則表達(dá)式就是一組高效的規(guī)則的模式集合
屿聋。
某個程序員的理解是:正則表達(dá)式是對字符串操作的一種邏輯公式空扎,就是用事先定義好的一些特定字符、及這些特定字符的組合润讥,組成一個“規(guī)則字符串”转锈,這個“規(guī)則字符串”用來表達(dá)對字符串的一種過濾邏輯。
0x02:Python中的正則表達(dá)式
正則表達(dá)式并不是Python的一部分楚殿,效率上可能不如str自帶的方法撮慨,但功能十分強(qiáng)大。
1.字符類
- 1.1一般字符(就是簡單的字符)
就是沒有任何正則元字符的正常字符串
比如匹配abcababc
將會找到兩個 abc
脆粥,需要注意的是匹配的時候是從前向后挨個匹配的砌溺,像 ababa
只能找到一個aba
- 1.2 \
將正則元字符(當(dāng)成正則式中的關(guān)鍵字)轉(zhuǎn)義成正常的字符。
import re #記得載入正則模塊
#case 1 沒有使用轉(zhuǎn)義
reStr='a.c'
targetStr="abc a.c a\\c"
re.findall(reStr,targetStr)
#結(jié)果是:
>>>['abc', 'a.c', 'a\\\\c']
解釋:因?yàn)槟氵@里沒有使用轉(zhuǎn)義变隔,所以a.c
中的.
就是一個正則元字符(.
的作用會在下面講解)规伐,所以上面的代碼會選出多個符合條件的子字符串。
#case 2 使用轉(zhuǎn)義
reStr='a\\.c'
re.findall(reStr,targetStr)
#結(jié)果是:
>>>['a.c',]
```
*解釋*:這樣就只把`a.c`給提取出來了弟胀。
- 1.3`.`
代替任何單個字符(換行除外)
```
reStr="a.c"
targetStr="abc a.c abb"
re.findall(reStr,targetStr)
>>>['abc','a.c']
```
- 1.4`[]`
對應(yīng)的位置可以是字符集的任何一個字符楷力。除了直接給出字符集喊式,你還可以給出字符范圍
```
#case 1:直接列出字符集
reStr="a[12bc]ef"
targetStr="a1ef abef a12bcef"
re.findall(reStr,targetStr)
>>>['a1ef', 'abef']
#case 2:使用范圍
reStr="a[1-5a-d]ef"
targetStr="a3ef a6ef acef a1eef"
re.findall(reStr,targetStr)
>>>['a3ef', 'acef']
#當(dāng)然[]中你還可以添加其他的規(guī)則
```
#### 2.預(yù)定義字符類(可以寫在[]中的)
- 2.1`\\d`和`\\D`
數(shù)字:`\\d`=`[0-9]`
非數(shù)字:`\\D`=`[^\\d]`=`[^0-9]`
```
targetStr="123abc"
#case 1:數(shù)字
reStr="\\d"
re.findall(reStr,targetStr)
>>>['1','2','3']
#case 2:非數(shù)字
reStr="\\D"
re.findall(reStr,targetStr)
>>>['a','b','c']
#case 3:非數(shù)字
reStr="[^0-9]"
re.findall(reStr,targetStr)
>>>['a','b','c']
```
*注意:不推薦使用`[^\\d]` 或者是`[^\\D]`的表示方式,如果你忘記了[],結(jié)果就會是錯誤的*
- 2.2`\\s`和`\\S`
空白字符:`\\s`=[<space>\\t\\r\\n\\f\\v]
非空白字符:`\\S`=[^\\s]
```
#case 1:空白字符
reStr="\\s"
targetStr="a\\nb a\\tb"
re.findall(reStr,targetStr)
>>>['\\n', ' ', '\\t']
#case 2:非空白字符
reStr="a\\Sc"
targetStr="abc a.c"
re.findall(reStr,targetStr)
>>>['abc', 'a.c']
```
空白字符是包括所有的空格字符萧朝,有的文本編輯器會使用<space>替代`tab` 鍵岔留,此時需要注意。`\\S`和`.`的區(qū)別是`.`包括了`\\S`.
- 2.3`\\w`和`\\W`
單詞字符:`\\w`=[A-Za-z0-9_]
非單詞字符:`\\W`=[^\\w]
```
#case 1:能夠組成單詞的字符
reStr="a\\wc"
targetStr="abca2caBca c"
re.findall(reStr,targetStr)
>>>['abc', 'a2c', 'aBc']
```
#### 3.數(shù)量詞(用字字符或是`()`之后)
- 3.1`*`
匹配請一個字符0次或者是無數(shù)次
```
reStr="a*c" #匹配 'c' 'ac' 'aac' 'a...c'
targetStr="ac aac abc aaac"
re.findall(reStr,targetStr)
>>>['ac', 'aac', 'c', 'aaac']
```
*注意abc中c是符合的*
- 3.2`+`
匹配前一個字符1次或者是無數(shù)次
```
reStr="a+c" #匹配 'ac' 'aac' 'a...c'
targetStr="ac aac abc aaac"
re.findall(reStr,targetStr)
>>>['ac', 'aac', 'aaac']
```
- 3.3`?`
匹配前一個字符0次或者是1次
```
reStr="a?c" #匹配 'c' 'ac'
targetStr="ac aac abc aaac"
re.findall(reStr,targetStr)
>>>['ac', 'ac', 'c','ac']
```
- 3.4`{m}`
匹配前一個字符m次
```
reStr="a{2}c" #只匹配 "aac"
targetStr="ac aac abc aaac"
re.findall(reStr,targetStr)
>>>['aac','aac']
```
- 3.5`{m,n}`
匹配前一個字符從m次到n次
當(dāng)只有m的時候表示m-無數(shù)次
當(dāng)只有n的時候表示0-n次
```
reStr="a{1,2}c" #只匹配 'ac' 'aac'
targetStr="ac aac abc aaac"
re.findall(reStr,targetStr)
>>>['ac', 'aac', 'aac']
```
#### 4.邊界匹配
- 4.1`^`
匹配字符串開頭
在多行模式中匹配每一行的開頭
```
#case 1:沒有開啟多行模式
reStr="^abc"
targetStr="abc\\nabcd\\nbabc"
re.findall(reStr,targetStr)
>>>['abc']
#case 2:開啟多行模式
r=re.compile(reStr,re.M)
r.findall(targetStr)
>>>['abc', 'abc']
```
- 4.2`$`
匹配字符串末尾
在多行模式中匹配每一行的末尾
```
reStr="-a$"
targetStr="abc-a\\n123-a\\n-a\\na\\n-b"
r=re.compile(reStr,re.M)
r.findall(targetStr)
>>>['-a', '-a', '-a']
```
- 4.3`\\A`
僅匹配字符串開頭
```
reStr="\\Aabc"
targetStr="abcabc"
re.findall(reStr,targetStr)
>>>['abc']
```
這個只會匹配字符串的開頭检柬,只要是開頭沒有的話那就是沒匹配上
- 4.4`\\Z`
僅匹配字符串結(jié)尾
```
reStr="abc\\Z"
targetStr="aaabc"
re.findall(reStr,targetStr)
>>['abd']
```
- 4.5`\\b`
匹配那些在單詞字符和非單詞字符之間的“位置”(之所以稱這個為位置献联,是因?yàn)檫@不是一個字符,比如`a-`中是在`a`和`-`之間的位置)何址,姑且認(rèn)為他是一個特殊字符吧里逆!
>注意在Python中`\\b`代表著是是退格鍵的意思,如果要使用正則表達(dá)式的話需要轉(zhuǎn)義以下用爪,就是使用`\\\\b`原押,當(dāng)然,你也可以使用`r'\\b'`使用Python的raw型的字符串(注意前面的`r`).其實(shí)就是內(nèi)部自動做了轉(zhuǎn)義偎血。
```
#case 1: 單純的`\\\\b`匹配問題
reStr="\\\\b"
targetStr="a a a"
re.findall(reStr,targetStr)
>>>['', '', '', '', '', '']
```
>為什么這里會是6個“位置”呢诸衔?注意的實(shí)際情況是這樣的:中間有兩個非單詞字符(空格),每個空格跟左右的單詞字符有4個“位置”颇玷,再加上整個字符串的首位2個位置笨农,所有有6個位置。是不是更加的深入了解了“位置”的意思了呢帖渠。
```
#case 2:字符和"\\\\b"的搭配使用
targetStr="ao-ao-ao"
reStr=r"ao\\b" #注意這里的`r`
re.findall(reStr,targetStr)
>>>['ao','ao','ao']
```
>這里就是查找`ao`后面跟個位置的模式谒亦,是不是很好理解了已經(jīng)。
- 4.6`\\B`
這個也和上一個一樣空郊,是一個特殊的位置份招。匹配的是單詞字符和單詞字符之間的位置。
```
#case 1: 單純的"\\\\B"
reStr="\\\\B"
targetStr="a _a"
re.findall(reStr,targetStr)
>>>['']
```
*解釋*:這里的結(jié)果就是在下劃線和`a`之間的這個位置渣淳。
```
#case 2:和其他模式搭配
reStr=r"a\\B"
targetStr="aa-aaa"
re.findall(reStr,targetStr)
>>>['a', 'a', 'a']
```
*解釋*:這里模式想找的是字符`a`并且a后面還有其他的單詞字符跟著脾还。如果換成target="aa-a_a"的話伴箩,那么結(jié)果就是只有兩個`a`被找到了入愧。
>寫在最后:今天是勞動節(jié)了,已經(jīng)在昨天爬了香山嗤谚,所以決定未來的三天假期就不出門了棺蛛。早上起了很晚,慢悠悠的處理了手頭上的一點(diǎn)工作巩步,然后一天完成了這點(diǎn)文章旁赊,終于對正則表達(dá)式有了點(diǎn)深刻的認(rèn)識。祝愿大家節(jié)日快樂椅野,勞動人民最光榮终畅!下一篇講解剩余的正則表達(dá)式的知識籍胯。
### 參考
- [正則表達(dá)式-wiki](http://www.wikiwand.com/en/Regular_expression)
- [正則表達(dá)式-在線測試](http://tool.oschina.net/regex/)
- [Python中的正則表達(dá)式](http://www.cnblogs.com/huxi/archive/2010/07/04/1771073.html)
- [re - Regular expression operations](https://docs.python.org/2/library/re.html)
- [Python中正則表達(dá)式模塊--`re`的使用](http://www.cnblogs.com/sevenyuan/archive/2010/12/06/1898075.html)