国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

Python3如何優(yōu)雅地使用正則表達式(詳解一)

2019-11-14 17:25:27
字體:
供稿:網(wǎng)友

注:本文翻譯自 Regular ExPRession HOWTO,小甲魚童鞋對此做了一些注釋和修改。


正則表達式介紹

正則表達式(Regular expressions 也稱為 REs,或 regexes 或 regex patterns)本質(zhì)上是一個微小的且高度專業(yè)化的編程語言。它被嵌入到 Python 中,并通過 re 模塊提供給程序猿使用。使用正則表達式,你需要指定一些規(guī)則來描述那些你希望匹配的字符串集合。這些字符串集合可能包含英語句子、 e-mail 地址、TeX 命令,或任何你想要的東東。

正則表達式模式被編譯成一系列的字節(jié)碼,然后由一個 C 語言寫的匹配引擎所執(zhí)行。對于高級的使用,你可能需要更關注匹配引擎是如何執(zhí)行給定的 RE,并通過一定的方式來編寫 RE,以便產(chǎn)生一個可以運行得更快的字節(jié)碼。本文暫不講解優(yōu)化的細節(jié),因為這需要你對匹配引擎的內(nèi)部機制有一個很好的理解。但本文的例子均是符合標準的正則表達式語法。

小甲魚注釋:Python 的正則表達式引擎是用 C 語言寫的,所以效率是極高的。另,所謂的正則表達式,這里說的 RE,就是上文我們提到的“一些規(guī)則”。

正則表達式語言相對較小,并且受到限制,所以不是所有可能的字符串處理任務都可以使用正則表達式來完成。還有一些特殊的任務,可以使用正則表達式來完成,但是表達式會因此而變得非常復雜。在這種情況下,你可能通過自己編寫 Python 代碼來處理會更好些;盡管 Python 代碼比一個精巧的正則表達式執(zhí)行起來會慢一些,但可能會更容易理解。

小甲魚注釋:這可能是大家常說的“丑話說在前”吧,大家別管他,正則表達式非常優(yōu)秀,她可以處理你 98.3% 的文本任務,一定要好好學哦~~~~~


簡單的模式

我們將從最簡單的正則表達式學習開始。由于正則表達式常用于操作字符串的,因此我們從最常見的任務下手:字符匹配。


字符匹配

大多數(shù)字母和字符會匹配它們自身。舉個例子,正則表達式 FishC 將完全匹配字符串 "FishC"。(你可以啟用不區(qū)分大小寫模式,這將使得 FishC 可以匹配 "FISHC" 或 "fishc",我們會在后邊討論這個話題。)

當然這個規(guī)則也有例外。有少數(shù)特殊的字符我們稱之為元字符(metacharacter),它們并不能匹配自身,它們定義了字符類、子組匹配和模式重復次數(shù)等。本文用很大的篇幅專門討論了各種元字符及其作用。

下邊是元字符的完整列表(我們將在后邊逐一講解):

.   ^   $   *   +   ?   { }   [ ]   /   |   ( )

小甲魚注釋:如果沒有這些元字符,正則表達式就變得跟字符串的 find() 方法一樣平庸了......


我們先來看下方括號 [ ],它們指定一個字符類用于存放你需要匹配的字符集合。可以單獨列出需要匹配的字符,也可以通過兩個字符和一個橫桿 - 指定匹配的范圍。例如 [abc] 會匹配字符 ab 或 c[a-c] 可以實現(xiàn)相同的功能。后者使用范圍來表示與前者相同的字符集合。如果你想只匹配小寫字母,你的 RE 可以寫成 [a-z]

需要注意的一點是:元字符在方括號中不會觸發(fā)“特殊功能”,在字符類中,它們只匹配自身。例如 [akm$] 會匹配任何字符 'a''k''m' 或 '$''$' 是一個元字符,但在方括號中它不表示特殊含義,它只匹配 '$' 字符本身。

你還可以匹配方括號中未列出的所有其他字符。做法是在類的開頭添加一個脫字符號 ^ ,例如 [^5] 會匹配除了 '5' 之外的任何字符。


或許最重要的元字符當屬反斜杠 / 了。跟 Python 的字符串規(guī)則一樣,如果在反斜杠后邊緊跟著一個元字符,那么元字符的“特殊功能”也不會被觸發(fā)。例如你需要匹配符號 [ 或 /,你可以在它們前面加上一個反斜杠,以消除它們的特殊功能:/[//

反斜杠后邊跟一些字符還可以表示特殊的意義,例如表示十進制數(shù)字,表示所有的字母或者表示非空白的字符集合。

小甲魚解釋:反斜杠真牛逼,反斜杠后邊跟元字符去除特殊功能,反斜杠后邊跟普通字符實現(xiàn)特殊功能。

讓我們來舉個例子:/w 匹配任何字符。如果正則表達式以字節(jié)的形式表示,這相當于字符類 [a-zA-Z0-9_];如果正則表達式是一個字符串,/w 會匹配所有 Unicode 數(shù)據(jù)庫(unicodedata 模塊提供)中標記為字母的字符。你可以在編譯正則表達式的時候,通過提供 re.ASCII 表示進一步限制 /w 的定義。

小甲魚解釋:re.ASCII 標志使得 /w 只能匹配 ASCII 字符,不要忘了,Python3 是 Unicode 的。

下邊列舉一些反斜杠加字符構成的特殊含義:

特殊字符含義
/d匹配任何十進制數(shù)字;相當于類 [0-9]
/D與 /d 相反,匹配任何非十進制數(shù)字的字符;相當于類 [^0-9]
/s匹配任何空白字符(包含空格、換行符、制表符等);相當于類 [ /t/n/r/f/v]
/S與 /s 相反,匹配任何非空白字符;相當于類 [^ /t/n/r/f/v]
/w匹配任何字符,見上方解釋
/W于 /w 相反
/b匹配單詞的開始或結束
/B與 /b 相反


它們可以包含在一個字符類中,并且一樣擁有特殊含義。例如 [/s,.] 是一個字符類,它將匹配任何空白字符(/s 的特殊含義),',' 或 '.'。 

最后我們要講的一個元字符是 .,它匹配除了換行符以外的任何字符。如果設置了 re.DOTALL 標志,. 將匹配包括換行符在內(nèi)的任何字符。


重復的事情

使用正則表達式能夠輕松的匹配不同的字符集合,但 Python 字符串現(xiàn)有的方法卻無法實現(xiàn)。然而,如果你認為這是正則表達式的唯一優(yōu)勢,那你就 too young too native 了。正則表達式有另一個強大的功能,就是你可以指定 RE 部分被重復的次數(shù)。


我們來看看 * 這個元字符,當然它不是匹配 '*' 字符本身(我們說過元字符都是有特殊能力的),它用于指定前一個字符匹配零次或者多次。

例如 ca*t 將匹配 ct(0 個字符 a),cat(1 個字符 a),caaat(3 個字符 a),等等。需要注意的是,由于受到 C 語言的 int 類型大小的內(nèi)部限制,正則表達式引擎會限制字符 'a' 的重復個數(shù)不超過 20 億個;不過,通常我們工作中也用不到那么大的數(shù)據(jù)。


正則表達式默認的重復規(guī)則是貪婪的,當你重復匹配一個 RE 時,匹配引擎會嘗試盡可能多的去匹配。直到 RE 不匹配或者到了結尾,匹配引擎就會回退一個字符,然后再繼續(xù)嘗試匹配。

我們通過例子一步步的給大家講解什么叫“貪婪”:先考慮一下表達式 a[bcd]*b,首先需要匹配字符 'a',然后是零個到多個 [bcd],最后以 'b' 結尾。那現(xiàn)在想象一下,這個 RE 匹配字符串 abcbd 會怎樣?

步驟匹配說明
1a匹配 RE 的第一個字符 'a'
2abcbd引擎在符合規(guī)則的情況下盡可能地匹配 [bcd]*,直到該字符串的結尾
3失敗引擎嘗試匹配 RE 最后一個字符 'b',但當前位置已經(jīng)是字符串的結尾,所以失敗告終
4abcb回退,所以 [bcd]* 匹配少一個字符
5失敗再一次嘗試匹配 RE 最后一個字符 'b',但字符串最后一個字符是 'd',所以失敗告終
6abc再次回退,所以 [bcd]* 這次只匹配 'bc'
7abcb再一次嘗試匹配字符 'b',這一次字符串當前位置指向的字符正好是 'b',匹配成功


最終,RE 匹配的結果是 abcb

小甲魚解釋:正則表達式默認的匹配規(guī)則是貪婪的,后邊有教你如何使用非貪婪的方法匹配。


另一個實現(xiàn)重復的元字符是 +,用于指定前一個字符匹配一次或者多次。

要特別注意 * 和 + 的區(qū)別:* 匹配的是零次或者多次,所以被重復的內(nèi)容可能壓根兒不會出現(xiàn);+ 至少需要出現(xiàn)一次。例如 ca+t 會匹配 cat 和 caaat,但不會匹配 ct


還有兩個表示重復的元字符,其中一個是問號 ?,用于指定前一個字符匹配零次或者一次。你可以這么想,它的作用就是把某種東西標志位可選的。例如 小?甲魚 可以匹配 小甲魚,也可以匹配 甲魚


最靈活的應該是元字符 {m, n}(m 和 n 都是十進制整數(shù)),上邊講到的幾個元字符都可以使用它來表達,它的含義是前一個字符必須匹配 m 次到 n 次之間。例如 a/{1, 3}b 會匹配 a/ba//b 和 a///b。但不會匹配 ab(沒有斜杠);也不會匹配a////b(斜杠超過三個)。

你可以省略 m 或者 n,這樣的話,引擎會假定一個合理的值代替。省略 m,將被解釋為下限 0;省略 n 則會被解釋為無窮大(事實上是上邊我們提到的 20 億)。

小甲魚解釋:如果是 {, n} 相當于 {0, n};如果是 {m, } 相當于 {m, +無窮};如果是 {n},則是重復前一個字符 n 次。


聰明的魚油應該已經(jīng)發(fā)現(xiàn)了,其實 *+ 和 ? 都可以使用 {m, n} 來代替。{0,} 跟 * 是一樣的;{1, } 跟 + 是一樣的;{0, 1}跟 ? 是一樣的。不過還是鼓勵大家記住并使用 *+ 和 ?,因為這些字符更短并且更容易閱讀。

小甲魚解釋:還有一個原因是匹配引擎對 * + ? 做了優(yōu)化,效率要更高些。




發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 安多县| 怀安县| 台州市| 新巴尔虎左旗| 沾化县| 新田县| 连江县| 红河县| 东海县| 达尔| 青冈县| 海兴县| 德庆县| 吴旗县| 东城区| 修武县| 西峡县| 东平县| 句容市| 青州市| 海伦市| 尼勒克县| 长兴县| 玉龙| 禄劝| 醴陵市| 泰兴市| 鹤山市| 彩票| 邵东县| 方山县| 广汉市| 玉树县| 原平市| 洛阳市| 凤阳县| 龙南县| 勃利县| 中西区| 界首市| 永靖县|