最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

Python_re(正則表達式)中文學習筆記

2022-02-19 10:34 作者:行遠自邇的孟秋  | 我要投稿


概述

正則表達式(稱為RE,或正則,或正則表達式模式)本質(zhì)上是嵌入在Python中的一種微小的、高度專業(yè)化的編程語言,可通過re模塊獲得。使用正則表達式,你需要指定一些規(guī)則來描述那些你希望匹配的字符串集合;此集合可能包含英語句子、電子郵件地址、TeX命令,或你喜歡的任何內(nèi)容。

正則表達式語言相對較小且受限制,因此并非所有可能的字符串處理任務(wù)都可以使用正則表達式完成。還有一些任務(wù)可以用正則表達式完成,但表達式變得非常復雜。在這些情況下,你最好編寫Python代碼來進行處理;雖然Python代碼比精心設(shè)計的正則表達式慢,但它也可能更容易理解。

簡單模式

我們首先要了解最簡單的正則表達式。由于正則表達式用于對字符串進行操作,因此我們將從最常見的任務(wù)開始:匹配字符。

匹配字符

大多數(shù)字母和字符只會匹配自己。例如:正則表達式test將完全匹配字符串test。(你可以啟用不區(qū)分大小寫的模式,讓這個正則匹配TestTEST,這個后面會詳細說。)

當然這條規(guī)則有例外;一些字符是特殊的,稱為元字符(metacharacters),它們并不能匹配自身,它們定義了字符類、子組匹配和模式重復次數(shù)等。會用很大的篇幅討論各種元字符及其功能。

元字符的完整列表:. ^ $ * + ? { } [ ] \ | ( )

方括號 [ ] ,用于指定字符類,可以單獨列出字符,也可以通過給出兩個字符并用 '-' 標記將它們分開來表示一系列字符。[abc] 將匹配任何字符 a 、b c ;這與 a-c 相同,它使用一個范圍來表示同一組字符。如果你只想匹配小寫字母,你的正則是 [a-z]

在方括號中的元字符不生效,例如,[akm$] 將匹配 'a' 、'k' 、'm''$' 中的任意字符;'$' 通常是一個元字符,但在一個字符類中它被剝奪了特殊性。

還可以通過 ^ 匹配設(shè)置的字符類中未列出的字符,在類的開頭添加 ^ ,[^5] 會匹配除了 '5' 之外的任何字符。如果插入符出現(xiàn)在字符類的其他位置,則它沒有特殊含義。例如:[5^] 將匹配 '5''^' 。


反斜杠?\ 是最重要的元字符,反斜杠后面可以跟各種字符,以指示各種特殊序列。它也用于轉(zhuǎn)移所有元字符,如果你需要匹配 [ \ ,你可以在它們前面加一個反斜杠來移除它們的特殊含義: \[ \\


注:一些以 '\' 開頭的特殊序列表示通常有用的預定義字符集,例如數(shù)字集、字母集或任何非空格的集合。讓我們舉個例子: \w 匹配任何字母數(shù)字字符。如果正則表達式模式以字節(jié)類表示,這相當于類 [a-zA-Z0-9] 。如果正則表達式是一個字符串, \w 將匹配由unicodedata模塊提供的Unicode數(shù)據(jù)庫中標記為字母的所有字符。通過在編譯正則表達式時提供re.ASCII標志,可以在字符串模式中使用更為受限制的 \w 定義。

以下為一些特殊序列的表格:

這些序列可以包含在字符類中。例如,[\s,.] 是一個匹配任何空格字符的字符類或者 ',' ,或 '.'


‘.’ 匹配除換行符之外的任何內(nèi)容,并且有一個可選模式(re.DOTALL)甚至可以匹配換行符。‘.’常用于你想匹配“任何字符”的地方。


重復

能夠匹配不同的字符集合是正則表達式可以做的第一件事,這對于字符串可用方法來說是不可能的。但是,如果這是正則表達式的唯一額外功能,那么它們就不會有太大的優(yōu)勢。另一個功能是你可以指定正則的某些部分必須重復一定次數(shù)。


重復中我們要了解的第一個元字符是 * * 與字面字符 '*' 不匹配;相反,它指定前一個字符可以匹配零次或多次,而不是恰好一次。

例如,ca*t將匹配 'ct' (0個 'a' 字符), 'cat' (1個 'a' ),'caaat' (3個 'a' 字符),等等。


類似 * 這樣的重復是貪婪的;當重復正則時,匹配引擎將嘗試盡可能多地重復它。如果模式地后續(xù)部分不匹配,則匹配引擎將回退并以較少的重復次數(shù)再次嘗試。


通過一個逐步的例子來講解“貪婪”,讓我們考慮 a[bcd]*b 。這個正則匹配字母 'a' ,類'[bcd]' 中的零或多個字母,最后以 'b' 結(jié)尾。現(xiàn)在想象一下這個正則與字符串 'abcbd' 匹配。

正則現(xiàn)在已經(jīng)結(jié)束了,它已經(jīng)匹配了 abcb?。這演示了匹配引擎最初如何進行,如果沒有找到匹配,它將逐步回退并一次又一次地重試正則的其余部分。它將回退,知道它為 [bcd]* 嘗試零匹配,如果隨后失敗,引擎將斷定該字符串與正則完全不匹配。


另一個重復的元字符是 + ,它匹配一次或多次。 要特別注意 *??和 +??之間的區(qū)別; * 匹配 零次 或更多次,因此重復的任何東西都可能根本不存在,而 + 至少需要一次。 使用類似的例子, ca+t 將匹配 'cat' (1 個 'a' ), 'caaat' (3 個 'a' ),但不會匹配 'ct' 。


還有兩個重復限定符。 問號字符 ? 匹配一次或零次;你可以把它想象成是可選的。 例如, home-?brew 匹配 'homebrew''home-brew' 。


最復雜的重復限定符是 {m,n} ,其中 mn 是十進制整數(shù)。 這個限定符意味著必須至少重復 m 次,最多重復 n 次。 例如, a/{1,3}b 將匹配 'a/b' 'a//b''a///b' 。 它不匹配沒有斜線的 'ab' ,或者有四個的 'a////b' 。


你可以省略 m 或 n ; 在這種情況下,將假定缺失值的合理值。 省略 m 被解釋為 0 下限,而省略 n 則為無窮大的上限。


還原論者的讀者可能會注意到其他三個限定符都可以用這種表示法表達。 {0,} * 相同, {1,} 相當于 + , {0,1}? 相同。 最好使用 * , + ? ,因為它們更短更容易閱讀。

使用正則表達式

現(xiàn)在我們開始寫一下簡單的正則表達式。re模塊提供了正則表達式引擎的接口,允許你將正則編譯為對象,然后用它們進行匹配。

re模塊是使用C語言編寫,所以效率要比用普通的字符串方法高很多;將正則表達式編譯(compile)也是為了進一步提高效率;后面會經(jīng)常提到“模式”,指的是正則表達式被編譯成的模式對象。

編譯正則表達式

正則表達式被編譯為模式對象,模式對象具有各種操作的方法,例如搜索模式匹配或執(zhí)行字符串替換。

re.compile()也接受一個可選的 flags ,用于開啟各種特殊功能和語法變化,我們會在后面一一介紹。

現(xiàn)在先看一個例子。

正則作為字符串傳遞給re.compile()。正則被處理為字符串,因為正則表達式并不是Python的核心部分,并沒有創(chuàng)建用于表達它們的特殊語法。(有些應(yīng)用程序根本不需要正則,因此不需要通過包含它們來擴展語言規(guī)范。)相反,re模塊只是Python附帶的C擴展模塊,就類似于socket或zlib模塊。


將正則放在字符串中可以使Python語言更簡單,但也有一些負面影響,下面我們就來談一談。

麻煩的反斜杠


如前所述,正則表達式使用反斜杠字符( '\' )來使得一些普通的字符擁有特殊的能力(例如 \d 表示匹配任何十進制數(shù)字),或剝奪一些特殊字符的能力(例如 \[ 表示匹配左方括號 '[' )。這會跟Python字符串中實現(xiàn)相同功能的字符發(fā)生沖突。


假設(shè)你想要在LaTex文件中使用正則表達式匹配字符串 '\section' 。因為反斜杠作為需要匹配的特殊字符,所以你需要在它前面加多一個反斜杠來剝奪它的特殊功能。所以我們會把正則表達式的字符寫成 '\\section' 。


但不要忘了,Python在字符串中同樣使用反斜杠來表示特殊意義。因此,如果我們想將 '\\section' 完整地傳給re.compile(),我們需要再次添加兩個反斜杠……


簡而言之,要匹配文字反斜杠,必須將 '\\\\' 寫為正則字符串,因為正則表達式必須是 \\ ,并且每個反斜杠必須表示為 \\ 在常規(guī)Python字符串字面中。在反復使用反斜杠的正則中,這會導致大量重復的反斜杠,并使得生成的字符串難以理解。


解決方案是使用Python的原始字符串表示法來表示正則表達式;反斜杠不以任何特殊的方式處理前綴為`'r'`的字符串字面,因此 r'\n' 是一個包含 '\' 'n' 的雙字符字符串,而 '\n' 是一個包含換行符的單字符字符串。正則表達式通常使用這種原始字符串表示法用Python代碼編寫。

應(yīng)用匹配

一旦你有一個表示編譯正則表達式的隊形,你用它做什么?模式對象有幾種方法和屬性。下面列舉最重要幾個:

如果沒有找到匹配, match() search() 返回? None 。如果它們成功, 一個 匹配對象 實例將被返回,包含匹配相關(guān)的信息:起始和終結(jié)位置、匹配的子串以及其它。

示例:

現(xiàn)在,你可以嘗試使用正則表達式 [a-z]+ 去匹配各種字符串。


例如:

因為 + 表示匹配一次或者多次,所以空字符串不能被匹配。因此,match()返回None。


現(xiàn)在,讓我們嘗試一下可以匹配的字符串:

match()返回一個匹配對象,我們可以把結(jié)果儲存到一個變量中以供稍后使用。


現(xiàn)在你可以檢查匹配對象以獲取有關(guān)匹配字符串的信息。匹配對象包含了很多方法和屬性;最重要的是:

舉例:

由于match()方法只檢查正則是否在字符串的開頭匹配,所以start()始終為零。但是,模式的search()方法會掃描字符串,因此在這種情況下匹配可能不會從零開始。:

在實際應(yīng)用中,最常見的方式是在變量中存儲匹配變量,然后檢查它是否為None。通常形式如下:

有兩種模式方法返回所有的匹配結(jié)果,一個是findall(),另一個是finditer()。

findall()返回匹配字符串的列表:

finditer()則是將匹配對象作為一個迭代器(iterator)返回:

模塊級函數(shù)

使用正則表達式也并非一定要創(chuàng)建模式對象然后調(diào)用它的匹配方法;re模塊還提供了一些全局函數(shù),例如match(), search(), findall(), sub()等等。這些函數(shù)的第一個參數(shù)是正則表達式字符串,其他參數(shù)跟模式對象同名的方法采用一樣的參數(shù);返回值也一樣,同樣是返回None或者匹配對象。


本質(zhì)上,這些函數(shù)只是為你創(chuàng)建一個模式對象,并在其上調(diào)用相關(guān)的函數(shù)。它們還將編譯好的對象存儲在緩存中,以便將來可以快速地直接調(diào)用。


那我們到底是應(yīng)該直接使用這些模塊級別的函數(shù)呢,還是先編譯一個模式對象,再調(diào)用模式對象的方法呢?這其實取決于正則表達式的使用頻率,如果說我們這個程序只是偶爾使用到正則表達式,那么全局函數(shù)是比較方便的;如果我們的程序是大量的使用正則表達式(例如在一個循環(huán)中使用),那么建議你使用后一種方法,因為預編譯的話可以節(jié)省一些函數(shù)調(diào)用。但如果是在循環(huán)外部,由于得益于內(nèi)部緩存機制,兩者效率相差無幾。

編譯標志

編譯標志允許你修改正則表達式的工作方式。標志在re模塊中有兩個名稱,長名稱如IGNORECASE和一個簡短的單字母形式,如I。(如果你熟悉Perl的模式修飾符,則單字母形式使用和其相同的字母;例如,re.VERBOSE的簡寫是er.X。) 多個標志可以通過按位或運算('|')來指定它們;例如, re.I | re.M 設(shè)置I和M標志。

這是一個可用的標志表,以及每個標志的更詳細說明。

A

ASCII

使 \w 、 \W \b 、 \B\s\S 只匹配ASCII字符而不是匹配完整的Unicode字符。這個標志僅對Unicode模式有意義,并且忽略字節(jié)模式。


S

DOTALL

使 . 可以匹配任何字符,包括換行符。如果沒有這個標志, . 將匹配除了換行符的任何字符。


I

IGNORECASE

字符類和文本字符串在匹配的時候不區(qū)分大小寫。例如正則表達式 [A-Z] 也將會匹配對應(yīng)的小寫字母。如果設(shè)置LOCALE,則不會考慮語言(區(qū)域)設(shè)置這方面的大小寫問題。


L

LOCALE

使 \w 、 \W 、 \b\B 依賴當前的語言(區(qū)域)環(huán)境,而不是Unicode數(shù)據(jù)庫。


M

MULTILINE

( ^$ 還沒有提到,后面會細講……)

通常 ^ 只匹配字符串的開頭,而 $ 則只匹配字符串的結(jié)尾。當制定了這個標志時, ^ 不僅匹配字符串的開頭,還匹配每一行的行首; $ 不僅匹配字符串的結(jié)尾,還匹配每一行的行尾。


X

VERBOSE

這個標志使你的正則表達式可以寫得更好看和更與條理,指定此標志后,將忽略正則字符串中的空格,除非空格位于字符類中和使用反斜杠轉(zhuǎn)移的空格;此標志還允許你將注釋放在正則中, # 符號后面的內(nèi)容是注釋,不會遞交給匹配引擎,除了出現(xiàn)在字符類中和使用反斜杠轉(zhuǎn)義的 # 。


下面是使用re.VERBOSE的例子,大家看正則表達式的可讀性是不是提高了不少:

如果沒有設(shè)置VERBOSE標志,那么同樣的正則表達式會寫成:

哪個可讀性更加高?相信大家心里有底了。


Python_re(正則表達式)中文學習筆記的評論 (共 條)

分享到微博請遵守國家法律
安福县| 白朗县| 八宿县| 伊通| 大渡口区| 都兰县| 白沙| 施甸县| 临潭县| 措勤县| 桃江县| 都安| 大港区| 澄江县| 嘉峪关市| 碌曲县| 丹阳市| 罗甸县| 旬邑县| 常宁市| 梁河县| 革吉县| 大连市| 拉孜县| 林口县| 海林市| 安塞县| 铁力市| 龙口市| 郓城县| 基隆市| 陈巴尔虎旗| 郎溪县| 安宁市| 武强县| 凌海市| 凤城市| 永靖县| 偏关县| 澜沧| 汉中市|