天天看點

《Python核心程式設計(第3版)》——1.2 特殊符号和字元

本節書摘來自異步社群《python核心程式設計(第3版)》一書中的第1章,第1.2節,作者[美] wesley chun(衛斯理 春),孫波翔 李斌 李晗 譯,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。

本節将介紹最常見的特殊符号和字元,即所謂的元字元,正是它給予正規表達式強大的功能和靈活性。表1-1列出了這些最常見的符号和字元。

《Python核心程式設計(第3版)》——1.2 特殊符号和字元
《Python核心程式設計(第3版)》——1.2 特殊符号和字元
《Python核心程式設計(第3版)》——1.2 特殊符号和字元
《Python核心程式設計(第3版)》——1.2 特殊符号和字元

表示擇一比對的管道符号(|),也就是鍵盤上的豎線,表示一個“從多個模式中選擇其一”的操作。它用于分割不同的正規表達式。例如,在下面的表格中,左邊是一些運用擇一比對的模式,右邊是左邊相應的模式所能夠比對的字元。

《Python核心程式設計(第3版)》——1.2 特殊符号和字元

有了這個符号,就能夠增強正規表達式的靈活性,使得正規表達式能夠比對多個字元串而不僅僅隻是一個字元串。擇一比對有時候也稱作并(union)或者邏輯或(logical or)。

點号或者句點(.)符号比對除了換行符n以外的任何字元(python正規表達式有一個編譯标記[s或者dotall],該标記能夠推翻這個限制,使點号能夠比對換行符)。無論字母、數字、空格(并不包括“n”換行符)、可列印字元、不可列印字元,還是一個符号,使用點号都能夠比對它們。

《Python核心程式設計(第3版)》——1.2 特殊符号和字元

問:怎樣才能比對句點(dot)或者句号(period)字元?

答:要顯式比對一個句點符号本身,必須使用反斜線轉義句點符号的功能,例如“.”。

還有些符号和相關的特殊字元用于在字元串的起始和結尾部分指定用于搜尋的模式。如果要比對字元串的開始位置,就必須使用脫字元(^)或者特殊字元a(反斜線和大寫字母a)。後者主要用于那些沒有脫字元的鍵盤(例如,某些國際鍵盤)。同樣,美元符号($)或者z将用于比對字元串的末尾位置。

使用這些符号的模式與本章描述的其他大多數模式是不同的,因為這些模式指定了位置或方位。之前的“核心提示”記錄了比對(試圖在字元串的開始位置進行比對)和搜尋(試圖從字元串的任何位置開始比對)之間的差别。正因如此,下面是一些表示“邊界綁定”的正規表達式搜尋模式的示例。

《Python核心程式設計(第3版)》——1.2 特殊符号和字元

再次說明,如果想要逐字比對這些字元中的任何一個(或者全部),就必須使用反斜線進行轉義。例如,如果你想要比對任何以美元符号結尾的字元串,一個可行的正規表達式方案就是使用模式.*$$。

特殊字元b和b可以用來比對字元邊界。而兩者的差別在于b将用于比對一個單詞的邊界,這意味着如果一個模式必須位于單詞的起始部分,就不管該單詞前面(單詞位于字元串中間)是否有任何字元(單詞位于行首)。同樣,b将比對出現在一個單詞中間的模式(即,不是單詞邊界)。下面為一些示例。

《Python核心程式設計(第3版)》——1.2 特殊符号和字元

盡管句點可以用于比對任意符号,但某些時候,可能想要比對某些特定字元。正因如此,發明了方括号。該正規表達式能夠比對一對方括号中包含的任何字元。下面為一些示例。

《Python核心程式設計(第3版)》——1.2 特殊符号和字元

關于crdp這個正規表達式有一點需要說明:如果僅允許“r2d2”或者“c3po”作為有效字元串,就需要更嚴格限定的正規表達式。因為方括号僅僅表示邏輯或的功能,是以使用方括号并不能實作這一限定要求。唯一的方案就是使用擇一比對,例如,r2d2|c3po。

然而,對于單個字元的正規表達式,使用擇一比對和字元集是等效的。例如,我們以正規表達式“ab”作為開始,該正規表達式隻比對包含字母“a”且後面跟着字母“b”的字元串,如果我們想要比對一個字母的字元串,例如,要麼比對“a”,要麼比對“b”,就可以使用正規表達式[ab],因為此時字母“a”和字母“b”是互相獨立的字元串。我們也可以選擇正規表達式a|b。然而,如果我們想要比對滿足模式“ab”後面且跟着“cd”的字元串,我們就不能使用方括号,因為字元集的方法隻适用于單字元的情況。這種情況下,唯一的方法就是使用ab|cd,這與剛才提到的r2d2/c3po問題是相同的。

除了單字元以外,字元集還支援比對指定的字元範圍。方括号中兩個符号中間用連字元(-)連接配接,用于指定一個字元的範圍;例如,a-z、a-z或者0-9分别用于表示大寫字母、小寫字母和數值數字。這是一個按照字母順序的範圍,是以不能将它們僅僅限定用于字母和十進制數字上。另外,如果脫字元(^)緊跟在左方括号後面,這個符号就表示不比對給定字元集中的任何一個字元。

《Python核心程式設計(第3版)》——1.2 特殊符号和字元

本節介紹最常用的正規表達式符号,即特殊符号、+和?,所有這些都可以用于比對一個、多個或者沒有出現的字元串模式。星号或者星号操作符()将比對其左邊的正規表達式出現零次或者多次的情況(在計算機程式設計語言和編譯原理中,該操作稱為kleene閉包)。加号(+)操作符将比對一次或者多次出現的正規表達式(也叫做正閉包操作符),問号(?)操作符将比對零次或者一次出現的正規表達式。

還有大括号操作符({}),裡面或者是單個值或者是一對由逗号分隔的值。這将最終精确地比對前面的正規表達式n次(如果是{n})或者一定範圍的次數;例如,{m,n}将比對m~n次出現。這些符号能夠由反斜線符号轉義;*比對星号,等等。

注意,在之前的表格中曾經多次使用問号(重載),這意味着要麼比對0次,要麼比對1次,或者其他含義:如果問号緊跟在任何使用閉合操作符的比對後面,它将直接要求正規表達式引擎比對盡可能少的次數。

“盡可能少的次數”是什麼意思?當模式比對使用分組操作符時,正規表達式引擎将試圖“吸收”比對該模式的盡可能多的字元。這通常被叫做貪婪比對。問号要求正規表達式引擎去“偷懶”,如果可能,就在目前的正規表達式中盡可能少地比對字元,留下盡可能多的字元給後面的模式(如果存在)。本章末尾将用一個典型的示例來說明非貪婪比對是很有必要的。現在繼續檢視閉包操作符。

《Python核心程式設計(第3版)》——1.2 特殊符号和字元

使用這些縮寫,可以表示如下一些更複雜的示例。

《Python核心程式設計(第3版)》——1.2 特殊符号和字元

現在,我們已經可以實作比對某個字元串以及丢棄不比對的字元串,但有些時候,我們可能會對之前比對成功的資料更感興趣。我們不僅想要知道整個字元串是否比對我們的标準,而且想要知道能否提取任何已經成功比對的特定字元串或者子字元串。答案是可以,要實作這個目标,隻要用一對圓括号包裹任何正規表達式。

當使用正規表達式時,一對圓括号可以實作以下任意一個(或者兩個)功能:

對正規表達式進行分組;

比對子組。

關于為何想要對正規表達式進行分組的一個很好的示例是:當有兩個不同的正規表達式而且想用它們來比較同一個字元串時。另一個原因是對正規表達式進行分組可以在整個正規表達式中使用重複操作符(而不是一個單獨的字元或者字元集)。

使用圓括号進行分組的一個副作用就是,比對模式的子字元串可以儲存起來供後續使用。這些子組能夠被同一次的比對或者搜尋重複調用,或者提取出來用于後續處理。1.3.9節的結尾将給出一些提取子組的示例。

為什麼比對子組這麼重要呢?主要原因是在很多時候除了進行比對操作以外,我們還想要提取所比對的模式。例如,如果決定比對模式w+-d+,但是想要分别儲存第一部分的字母和第二部分的數字,該如何實作?我們可能想要這樣做的原因是,對于任何成功的比對,我們可能想要看到這些比對正規表達式模式的字元串究竟是什麼。

如果為兩個子模式都加上圓括号,例如(w+)-(d+),然後就能夠分别通路每一個比對子組。我們更傾向于使用子組,這是因為擇一比對通過編寫代碼來判斷是否比對,然後執行另一個單獨的程式(該程式也需要另行建立)來解析整個比對僅僅用于提取兩個部分。為什麼不讓python自己實作呢?這是re子產品支援的一個特性,是以為什麼非要重蹈覆轍呢?

《Python核心程式設計(第3版)》——1.2 特殊符号和字元

我們還沒介紹過的正規表達式的最後一個方面是擴充表示法,它們是以問号開始(?…)。我們不會為此花費太多時間,因為它們通常用于在判斷比對之前提供标記,實作一個前視(或者後視)比對,或者條件檢查。盡管圓括号使用這些符号,但是隻有(?p)表述一個分組比對。所有其他的都沒有建立一個分組。然而,你仍然需要知道它們是什麼,因為它們可能最适合用于你所需要完成的任務。

《Python核心程式設計(第3版)》——1.2 特殊符号和字元