首頁>技術>

回顧

上節我們說到Python正則表示式的基本字元,以及這些字元的用法

今天,我們繼續講講Python中一些擴充套件標記法,以及一些特殊序列

擴充套件標記法

(?...): 這種擴充套件標記法以括號內?開頭,其後第一個字元決定了採用什麼樣的語法。

1、(?aiLmsux)介紹

在?後面新增( 'a', 'i', 'L', 'm', 's', 'u', 'x'中的一個或多個),然後加上匹配規則。

這些字元對正則表示式設定以下標記,免去設定 flag 引數

'a' ==> re.A(re.ASCII) ==> 只匹配 ASCII 字元'i' ==> re.I(re.IGNORECASE) ==> 忽略大小寫'L' ==> re.L(re.LOCALE) ==> 由當前語言區域決定 \w, \W, \b, \B 和大小寫敏感匹配,不推薦使用。'm' ==> re.M(re.MULTILINE) ==> 多行模式's' ==> re.S(re.DOTALL) ==> .匹配全部字元'u' ==> re.U ==> Unicode匹配,Python3預設開啟這個模式'x' ==> re.X(re.VERBOSE) ==> 冗長模式

注意:'a', 'L', 'u' 作為內聯標記是相互排斥的,它們不能結合在一起

示例
# 忽略大小寫re.findall('(?i)ab', 'Ab')# out: ['Ab']# 連用s、ire.findall('(?si)ab.', 'Ab\n')# out: ['Ab']# 多行模式re.findall('^a.', 'ab\nac')# out: ['ab']re.findall('(?m)^a.', 'ab\nac')# out: ['ab', 'ac']# .匹配全部字元re.findall('(?s)ab.', 'ab\n')# out: ['ab\n']# 冗長模式# 這個標記允許你編寫更具可讀性更友好的正則表示式。# 透過分段和添加註釋,其中空白符號會被忽略re.findall(r"""(?x)\d +  # 整數位                \.       # 小數點                \d *     # 小數位                """, '3.1415na')# out: ['3.1415']
2、(?:…)介紹

括號分組的非捕獲版本,該分組所匹配的子字串 不能 在執行匹配後被獲取或是在之後的模式中被引用

可以配合 | 和 {m} 使用

示例
re.findall('(abc){2}', 'abcabc')# out: ['abc']re.findall('(?:abc){2}', 'abcabc')# out: ['abcabc']# 可以看出,捕獲版本和非捕獲版本的區別# 捕獲版本會捕獲到()分組內的匹配字元# 非捕獲版本會將()分組內的字元與外面的字元作為一個整體返回# 看一個巢狀捕獲的例子re.findall('(a(bc))cbs', 'abccbs')# out: [('abc', 'bc')]re.findall('(a(?:bc))cbs', 'abccbs')# out: ['abc']re.findall('(abc)|cbs', 'cbs')# out: ['']re.findall('(?:abc)|cbs', 'cbs')# out: ['cbs']
3、(?P<name>…) 和 (?P=name)介紹(?P<name>…)

為分組再指定一個組合名

每個組合名只能用一個正則表示式定義,只能定義一次

(?P=name)

反向引用一個命名組合

匹配前面那個名字叫 name 的命名組中匹配到的字串

示例
re.findall('(?P<name>abc)\\1', 'abcabc')re.findall('(?P<name>abc)(?P=name)', 'abcabc')# out: ['abc']
4、(?#…)介紹

註釋資訊,裡面的內容會被忽略。

示例
re.findall('abc(?#這是註釋)123', 'abc123')# out: ['abc123']
5、(?=…), (?!…)介紹(?=…):匹配 … 的內容。這個叫 lookahead assertion (後視斷言)(?!…):匹配 … 不符合的情況。這個叫 negative lookahead assertion(前視取反)

哈哈,是不是沒看懂,沒事,舉個栗子

示例
re.findall('Isaac (?=Asimov)', 'Isaac Asimov, Isaac Ash')# out: ['Isaac ']# 只有後面是 'Asimov' 的時候才匹配前面的 'Isaac 're.findall('Isaac. (?!Asimov)', 'Isaac1 Asimov, Isaac2 Ash')# out: ['Isaac2 ']# 為了顯示區別,我們加了 '.' 匹配數字 1、2# 從中可以看出,只有後面 不 是 'Asimov' 的時候才匹配 'Isaac ' 

看看,是不是一下子就明瞭了。

6、(?<=…), (?<?…)介紹匹配當前位置之前是 ... 的樣式。這個叫 positive lookbehind assertion (正向後視斷定)匹配當前位置之前不是 ... 的樣式。這個叫 negative lookbehind assertion (後視取反)

哈哈,這個又看不懂?

思考一下,既然有根據後面字元斷言的,那麼根據前面字元來斷言,也是很合理的,

示例
re.findall('(?<=Isaac )Asimov.', 'Isaac Asimov1, Asimov2')# out: ['Asimov1']re.findall('(?<!Isaac )Asimov.', 'Isaac Asimov1, Asimov2')# out: ['Asimov2']
7、(?(id/name)yes-pattern|no-pattern)介紹

如果給定的 id 或 name 存在,將會嘗試匹配 yes-pattern,否則就嘗試匹配 no-pattern,no-pattern 可選,也可以被忽略。

是不是有點像if else三目運算,其中 id 和 name 是分組 id、和指定的分組名 name

照舊,舉個栗子吧

示例
re.findall('(<)?(\w+@\w+(?:\.\w+))(?(1)>|$)', '<[email protected]>')# out: [('<', '[email protected]')]re.findall('(<)?(\w+@\w+(?:\.\w+))(?(1)>|$)', '[email protected]>')# out: []re.findall('(<)?(\w+@\w+(?:\.\w+))(?(1)>|$)', '<[email protected]')# out: [('', '[email protected]')]re.findall('(<)?(\w+@\w+(?:\.\w+))(?(1)>|$)', '[email protected]')# out: [('', '[email protected]')]

看了栗子是不是有點糊塗呢,我們來解析一下這個正則表示式

第一個括號捕獲的是 <? 是判斷 < 是否存在第二個括號,裡面是郵箱的格式,\w 代表數字、字母和下換線集合第三個括號巢狀在第二個當中,而且宣告非捕獲版本,是郵箱 . 及後面的字元最後一個括號當中,?(1)>|$:其中1 是對第一個括號分組的引用,如果存在,就匹配 >,否則匹配空

其結果匹配的就是<[email protected]>和[email protected]

而不會匹配 <[email protected]' 和 <[email protected]

但是上面的第三個結果為啥不一樣呢?

因為findall允許返回空匹配的,在有 ?的情況下,所以它會分兩種情況去匹配

在<存在的情況下,匹配不到 >,在<不存在時,能匹配到 [email protected]特殊序列字元描述簡單示例
re.findall('(ab)c\\1', 'abcab')# out: ['ab']# 注意,這裡需要 \\,等同於 r'(ab)c\1'# 為了方便,我們下面都使用 r''re.findall(r'\Aabc', 'abccadc\nabc')re.findall(r'^abc', 'abccadc\nabc')# out: ['abc']# 只有開頭的 abc 匹配了re.findall(r'\bHello\b', 'Hello world! Hellooo')# out: ['Hello']# 注意,通常 \b 定義為 \w 和 \W 字元之間,或者 \w 和字串開始/結尾的邊界re.findall(r'\bHello\b', 'Hello world! Hello.')# out: ['Hello', 'Hello']re.findall(r'\BHello\B', 'Hello worldHello123')# out: ['Hello']# Hello 兩邊都需要 \b 未定義的分隔字元re.findall(r'\d+', 'ab123d\nabc')# out: ['123']re.findall(r'\D+', 'ab123d\nabc')# out: ['ab', 'd\nabc']re.findall(r'\s+', 'ab12 3d\nab\tc')# out: [' ', '\n', '\t']re.findall(r'\S+', 'ab12 3d\nab\tc')# out: ['ab12', '3d', 'ab', 'c']re.findall(r'\w+', '[email protected]')# out: ['user_name', 'host163', 'com']re.findall(r'\W+', '[email protected]')# out: ['@', '.']re.findall(r'dd\Z', 'abddacdd')re.findall(r'dd$', 'abddacdd')# out: ['dd']
總結

今天講了一些擴充套件標記法,其實沒那麼難,多看看例子,多練習練習。

下節將介紹 re 模組各函式的用法,敬請期待......

13
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • Python 正則表示式(三)