03.編程學(xué)習(xí)--正則表達(dá)式(入門一)

文:鄭元春

人生苦短贝乎,我用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)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市离福,隨后出現(xiàn)的幾起案子杖狼,更是在濱河造成了極大的恐慌,老刑警劉巖妖爷,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蝶涩,死亡現(xiàn)場離奇詭異,居然都是意外死亡絮识,警方通過查閱死者的電腦和手機(jī)绿聘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來次舌,“玉大人熄攘,你說我怎么就攤上這事”四睿” “怎么了鲜屏?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長国拇。 經(jīng)常有香客問我洛史,道長,這世上最難降的妖魔是什么酱吝? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任也殖,我火速辦了婚禮,結(jié)果婚禮上务热,老公的妹妹穿的比我還像新娘忆嗜。我一直安慰自己,他們只是感情好崎岂,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布捆毫。 她就那樣靜靜地躺著,像睡著了一般冲甘。 火紅的嫁衣襯著肌膚如雪绩卤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天江醇,我揣著相機(jī)與錄音濒憋,去河邊找鬼。 笑死陶夜,一個胖子當(dāng)著我的面吹牛凛驮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播条辟,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼黔夭,長吁一口氣:“原來是場噩夢啊……” “哼宏胯!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起本姥,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤胳嘲,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后扣草,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體了牛,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年辰妙,在試婚紗的時候發(fā)現(xiàn)自己被綠了鹰祸。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡密浑,死狀恐怖蛙婴,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情尔破,我是刑警寧澤街图,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站懒构,受9級特大地震影響餐济,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜胆剧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一絮姆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧秩霍,春花似錦篙悯、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至颠悬,卻和暖如春矮燎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背椿疗。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工漏峰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留糠悼,地道東北人届榄。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像倔喂,于是被迫代替她去往敵國和親铝条。 傳聞我的和親對象是個殘疾皇子靖苇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容