目的:把數字后面不為abc的字符串找出來
如1ab符合要求,2abc不符合要求
1 str = '1ab' 2 out = re.match(r'\d+(?!abc)',str) 3 4 str1 = '1abc' 5 out1 = re.match(r'\d+(?!abc)',str1) 6 7 print('out:',out) 8 print('out1:',out1) 9 # 10 #out: <_sre.SRE_Match object; span=(0, 1), match='1'> 11 #out1: None 12 #
如果把(?!abc)改為[^abc],效果如下:
1 str = '1ab' 2 out3 = re.match(r'\d+[^abc]',str) 3 4 str1 = '1abc' 5 out4 = re.match(r'\d+[^abc]',str1) 6 7 print('out:',out3) 8 print('out1:',out4) 9 10 # 11 #out3: None 12 #out4: None
總結:
(?!abc)是把abc當做一個整體進行匹配,字符串中不存在abc才能成功,abc作為一個整體進行匹配
[^abc]只要字符串中存在a/b/c中的任一個即匹配不成功,字符串中不能出現a/b/c中的任一個
------------------------------------------------------------------
更新:
之前沒有注意到(?!abc)方式匹配字符串不消耗字符串內容這句話,導致如果字符串中間排除一個子字符串時會出現錯誤。
更新關於這部分的理解
(?=...) # 匹配字符串,且緊挨着匹配的字符串之后的字符等於...,才算匹配成功,且不消耗字符串內容
(?!...) # 匹配字符串,且緊挨着匹配的字符串之后的字符不等於...,才算匹配成功,且不消耗字符串內容
(?<=...) # 匹配字符串,且緊挨着匹配的字符串之前的字符等於...,才算匹配成功,且不消耗字符串內容
(?<!...) # 匹配字符串,且緊挨着匹配的字符串之前的字符不等於...,才算匹配成功,且不消耗字符串內容
具體理解:
以(?=...)為例
1 reg = re.compile('A(?=BC)') 2 reg.search('ABC') 3 reg.search('ABCDE') 4 5 6 # 輸出: 7 # <_sre.SRE_Match object; span=(0, 1), match='A'> 8 # <_sre.SRE_Match object; span=(0, 1), match='A'>
1 reg_1 = re.compile('A(?=BC)D') 2 print(reg_1.search('ABCD')) 3 4 5 # 輸出 6 # None
reg = re.compile('A(?=BC)')
reg.search('ABC')
在這種情況下,匹配一個字符,這個字符包含'A',且'A'后面的字符為'BC',字符串'ABCD'符合規律
但是,
reg_1 = re.compile('A(?=BC)D')
reg_1.search('ABCD')
就會出現問題,因為(?=...)括號內的表達式不消耗字符,也就是說匹配完字符串中的'A'之后,會判斷A之后的字符是否是'BC',匹配成功后正則表達式會繼續匹配字符串中'A'之后的字符是否是'D'
但是,在字符串中'A'之后是'B'就會出現匹配失敗,返回None.
https://blog.csdn.net/lxcnn/article/details/4304651 在這個鏈接中,解釋比較清楚.
在正則匹配過程中,各個子表達式會依次取得控制權,對字符串進行匹配.
比如例子中的
reg_1 = re.compile('A(?=BC)D')
1.'A(?=BC)D' 中,表達式'A'首先取得控制權,從字符串'ABCD'的開始位置('A'之前)進行匹配;
匹配成功,控制權交給下一個正則子表達式(?=BC),匹配位置移動到字符串'ABCD'中的'A'之后('B'之前)
2.正則子表達式(?=BC)取得控制權,對當前匹配位置的右側字符進行匹配,判斷是否等於(?=BC)中的'BC'(即'A'后的'BC');
匹配成功,控制權交給下一個正則子表達式'D',但是,因為(?=...)表達式不消耗字符,也就是說這個表達式是零寬度的,因此匹配位置不會往后移動.匹配位置依然在'A'之后.
3.正則子表達式'D'取得控制權,對當前位置('A'之后'B'之前)的右側字符進行匹配,判斷'A'之后的字符是否等於'D'.
字符串'ABCD'中,'A'之后為'B',匹配失敗
4.進行下一輪匹配,又回到表達式'A'取得控制權,開始匹配位置不再是字符串首位置,此時從字符串'ABCD'中的'A'之后'B'之前的位置開始匹配,重復1~3步驟,不斷移動匹配位置進匹配
整個正則表達式匹配過程明了了.
不消耗字符串的意思就是這個子表達式為零寬度的,在匹配結束后不會向后移動匹配位置
