Python正則表達式(二)

回顧

上節(jié)我們說到Python正則表達式的基本字符,以及這些字符的用法

今天,我們繼續(xù)講講Python中一些擴展標(biāo)記法,以及一些特殊序列

擴展標(biāo)記法

(?...): 這種擴展標(biāo)記法以括號內(nèi)?開頭,其后第一個字符決定了采用什么樣的語法。

1、(?aiLmsux)

介紹

?后面添加( 'a', 'i', 'L', 'm', 's', 'u', 'x'中的一個或多個),然后加上匹配規(guī)則。

這些字符對正則表達式設(shè)置以下標(biāo)記,免去設(shè)置 flag 參數(shù)

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

注意'a', 'L', 'u' 作為內(nèi)聯(lián)標(biāo)記是相互排斥的,它們不能結(jié)合在一起

示例

# 忽略大小寫
re.findall('(?i)ab', 'Ab')
# out: ['Ab']

# 連用s、i
re.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']

# 冗長模式
# 這個標(biāo)記允許你編寫更具可讀性更友好的正則表達式。
# 通過分段和添加注釋,其中空白符號會被忽略
re.findall(r"""(?x)\d +  # 整數(shù)位
                \.       # 小數(shù)點
                \d *     # 小數(shù)位
                """, '3.1415na')
# out: ['3.1415']

2、(?:…)

介紹

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

可以配合 |{m} 使用

示例

re.findall('(abc){2}', 'abcabc')
# out: ['abc']

re.findall('(?:abc){2}', 'abcabc')
# out: ['abcabc']

# 可以看出,捕獲版本和非捕獲版本的區(qū)別
# 捕獲版本會捕獲到()分組內(nèi)的匹配字符
# 非捕獲版本會將()分組內(nèi)的字符與外面的字符作為一個整體返回
# 看一個嵌套捕獲的例子
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、(?#…)

介紹

注釋信息,里面的內(nèi)容會被忽略。

示例

re.findall('abc(?#這是注釋)123', 'abc123')
# out: ['abc123']

5、(?=…), (?!…)

介紹

  • (?=…):匹配 的內(nèi)容。這個叫 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 ']
# 為了顯示區(qū)別,我們加了 '.' 匹配數(shù)字 1、2
# 從中可以看出,只有后面 不 是 'Asimov' 的時候才匹配 'Isaac ' 

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

6、(?<=…), (?<?…)

介紹

  • 匹配當(dāng)前位置之前是 ... 的樣式。這個叫 positive lookbehind assertion (正向后視斷定)
  • 匹配當(dāng)前位置之前不是 ... 的樣式。這個叫 negative lookbehind assertion (后視取反)

哈哈,這個又看不懂?

思考一下,既然有根據(jù)后面字符斷言的,那么根據(jù)前面字符來斷言,也是很合理的,

示例

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-pattern,no-pattern 可選,也可以被忽略。

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

照舊,舉個栗子吧

示例

re.findall('(<)?(\w+@\w+(?:\.\w+))(?(1)>|$)', '<username@host.com>')
# out: [('<', 'username@host.com')]

re.findall('(<)?(\w+@\w+(?:\.\w+))(?(1)>|$)', 'username@host.com>')
# out: []

re.findall('(<)?(\w+@\w+(?:\.\w+))(?(1)>|$)', '<username@host.com')
# out: [('', 'username@host.com')]

re.findall('(<)?(\w+@\w+(?:\.\w+))(?(1)>|$)', 'username@host.com')
# out: [('', 'username@host.com')]

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

  • 第一個括號捕獲的是 <
  • ? 是判斷 < 是否存在
  • 第二個括號,里面是郵箱的格式,\w 代表數(shù)字、字母和下?lián)Q線集合
  • 第三個括號嵌套在第二個當(dāng)中,而且聲明非捕獲版本,是郵箱 . 及后面的字符
  • 最后一個括號當(dāng)中,?(1)>|$:其中1 是對第一個括號分組的引用,如果存在,就匹配 >,否則匹配空

其結(jié)果匹配的就是<username@host.com>username@host.com。

而不會匹配 <user@host.com' 和 <user@host.com

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

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

  • <存在的情況下,匹配不到 >,
  • <不存在時,能匹配到 username@host.com

特殊序列

字符描述

image.png

簡單示例

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 和字符串開始/結(jié)尾的邊界

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+', 'user_name@host163.com')
# out: ['user_name', 'host163', 'com']

re.findall(r'\W+', 'user_name@host163.com')
# out: ['@', '.']

re.findall(r'dd\Z', 'abddacdd')
re.findall(r'dd$', 'abddacdd')
# out: ['dd']

總結(jié)

今天講了一些擴展標(biāo)記法,其實沒那么難,多看看例子,多練習(xí)練習(xí)。

下節(jié)將介紹 re 模塊各函數(shù)的用法,敬請期待......

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容