正則表示式取反_Python正則表示式(二)
技術標籤:正則表示式取反
回顧
上節我們說到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)
介紹
如果給定的 id
或 name
存在,將會嘗試匹配 yes-pattern
,否則就嘗試匹配 no-pattern
,no-pattern
可選,也可以被忽略。
是不是有點像if else
三目運算,其中 id
和 name
是分組 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]
特殊序列
字元描述
簡單示例
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
模組各函式的用法,敬請期待......