1. 程式人生 > 其它 >正則表示式取反_Python正則表示式(二)

正則表示式取反_Python正則表示式(二)

技術標籤:正則表示式取反

65807d003c2d169ad35153bae786b9f1.png

回顧

上節我們說到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、i
re.findall('(?si)ab.', 'Abn')
# out: ['Ab']

# 多行模式
re.findall('^a.', 'abnac')
# out: ['ab']
re.findall('(?m)^a.', 'abnac')
# out: ['ab', 'ac']

# .匹配全部字元
re.findall('(?s)ab.', 'abn')
# out: ['abn']

# 冗長模式
# 這個標記允許你編寫更具可讀性更友好的正則表示式。
# 通過分段和添加註釋,其中空白符號會被忽略
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)

介紹

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

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

照舊,舉個栗子吧

示例

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

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

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

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

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

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

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

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

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

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

  • <存在的情況下,匹配不到 >
  • <不存在時,能匹配到 [email protected]

特殊序列

字元描述

019466975f3d47ec1e946ee9270adb37.png

簡單示例

re.findall('(ab)c1', 'abcab')
# out: ['ab']
# 注意,這裡需要 ,等同於 r'(ab)c1'
# 為了方便,我們下面都使用 r''

re.findall(r'Aabc', 'abccadcnabc')
re.findall(r'^abc', 'abccadcnabc')
# out: ['abc']
# 只有開頭的 abc 匹配了

re.findall(r'bHellob', 'Hello world! Hellooo')
# out: ['Hello']
# 注意,通常 b 定義為 w 和 W 字元之間,或者 w 和字串開始/結尾的邊界

re.findall(r'bHellob', 'Hello world! Hello.')
# out: ['Hello', 'Hello']

re.findall(r'BHelloB', 'Hello worldHello123')
# out: ['Hello']
# Hello 兩邊都需要 b 未定義的分隔字元

re.findall(r'd+', 'ab123dnabc')
# out: ['123']

re.findall(r'D+', 'ab123dnabc')
# out: ['ab', 'dnabc']

re.findall(r's+', 'ab12 3dnabtc')
# out: [' ', 'n', 't']

re.findall(r'S+', 'ab12 3dnabtc')
# 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'ddZ', 'abddacdd')
re.findall(r'dd$', 'abddacdd')
# out: ['dd']

總結

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

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