python 正则表达式 断言 不定长表达式_MyEssay 之 Python正则表达式 —— 四种断言扩展的理解...
我們經(jīng)常用正則表達(dá)式來檢測一個字符串中包含某個子串,要表示一個字符串中不包含單個的某字符或某些字符也很容易,用[^...]形式就可以了。但是要表示一個字符串中不包含某個子串(由字符序列構(gòu)成)的時候,用[^...]這種形式就不行了,此時就需要使用到四種正則表達(dá)式的擴(kuò)展匹配了,即所謂的“正向前行匹配” ?(?=...)、“負(fù)向前行匹配” (?!...)、"正向后行匹配" (?<=...) ?、“負(fù)向后行匹配”(?文中的描述,從兩個方面入手:
所謂的前行(lookahead)和后行(lookbehind),其實(shí)就是向前看和向后看的意思。正則表達(dá)式引擎在執(zhí)行字符串和表達(dá)式匹配時,會從頭到尾(從前到后)連續(xù)掃描字符串中的字符,設(shè)想有一個掃描指針指向字符邊界處并隨匹配過程移動。前行斷言,是當(dāng)掃描指針位于某個位置時,引擎會嘗試匹配指針還未掃過的字符,先于指針到達(dá)該字符,故稱為前行。后行斷言,引擎會嘗試匹配指針已掃過的字符,后于指針到達(dá)該字符,故稱為后行。
記憶方式:后行斷言(?<=pattern)、(?
所謂的正向(positive)和負(fù)向(negative):正向就表示匹配括號中的表達(dá)式,負(fù)向表示不匹配。
記憶方式:不等于(!=)、邏輯非(!)都是用!號來表示,所以有!號的形式表示不匹配、負(fù)向;將!號換成=號,就表示匹配、正向。
我們特別需要注意的一點(diǎn)是,對于后行方式的兩種斷言(?<=...)和(?
line0 = ‘?#?def???func(funcName, funcParam, funcTime=360) ‘
line1 =?‘?def???func(funcName, funcParam, funcTime=360) ‘
line2 =?"????obj1(param).func(‘func1‘, ‘param1‘, funcTime=150) # test"
line3 =?"??obj2().funcTest(1) ?# obj1(param).func(‘func1‘, ‘param1‘)"
我們希望字符串中包含對函數(shù) func()的調(diào)用,即在被測試line中出現(xiàn) "func("字符串,但是在被測line中卻又不包含針對函數(shù)func的定義,即不能出現(xiàn) “def func(” 字符串,并且def 和 func 之間可能包含多個空格。按照最直接的思路,為要匹配 "func("?字符串,并且是在 "func("?前面不出現(xiàn) “def\s+”模式的字符串,所以首先考慮使用向后看的方法,即負(fù)向后行匹配方式來應(yīng)用于line1,即 re.findall(r"(?
>>> re.findall(r"(?
[‘???func(‘]
"func"前為三個空格;這是為什么呢?原因是re引擎會去嘗試找到一個 "\s*func\(" 模式的字符串,并且在這個字符串前面不會出現(xiàn) "def?"?字符串(def后有一個空格),包含三個前置空格的 "???func("?正好就能滿足條件,首先它能夠匹配 "\s*func\(" 的模式,并且這個字符串前面的是不含空格的 "def" 字符串,而不是在負(fù)向后行匹配斷言(?
那么嘗試將負(fù)向后行匹配斷言中def后面的空格去掉,即修改為?re.findall("(?
>>> re.findall(r"(?
[‘??func(‘]
"func"前為兩個空格——仔細(xì)分析會發(fā)現(xiàn)這是因?yàn)樵蚴莚e引擎會去嘗試找到一個“\s*func\(”模式的字符串,并且在這個字符串前面不會出現(xiàn)“def”字符串(def后沒有空格),包含2個前置空格的 "??func(" 就正好滿足條件,因?yàn)榘?個空格的 "??func("?字符串能夠匹配 "\s*func\(" 的模式,并且這個字符串前面的是后接了一個空格的 "def?"?字符串,而不是在負(fù)向后行匹配斷言pattern "(?
再嘗試在負(fù)向后行匹配斷言中在def后面使用\s+,即修改為??re.findall("(?
——所以,對于在 def 和 func之間包含了三個空格的line1,要想用負(fù)向后行斷言來實(shí)現(xiàn)匹配,必須使用def后包含三個空格而func前無空格的?re.findall("(?
于是我們只能考慮采取負(fù)向前行斷言來實(shí)現(xiàn)精確匹配,即 re.findall("^(?!.*def\s+func\().*func\(", line1),執(zhí)行得到的結(jié)果為空列表[],同時我們使用正向前行斷言來驗(yàn)證我們的匹配字符串使用正確,即執(zhí)行?re.findall("^(?=.*def\s+func\().*func\(", line1),得到的結(jié)果為?[‘def ? func(‘]
>>> re.findall("^(?!.*def\s+func\().*func\(", line1)
[]
>>> re.findall("^(?=.*def\s+func\().*func\(", line1)
[‘?def???func(‘]
—— 這說明我們的負(fù)向前行斷言正好精確匹配到了 def 和 func 之間存在不定長度空格數(shù)的情況。
此處再來解析一下這里的負(fù)向前行斷言的含義:"^(?!.*def\s+func\().*func\(" ?表示從line的起始位置開始向后搜索,不允許出現(xiàn) ".*def\s+func\(" 這種模式的字符串,但又嘗試在此前提下尋找能夠匹配 ?".*func\(" 模式的字符串,這也就正是我們所希望的過濾條件。此處的?(?!.*def\s+func\()?是不消耗任何字符串長度的
這里需要特別注意的是另外兩種與 re.findall("^(?!.*def\s+func\().*func\(", line1) 很接近的匹配模式:
1、如果使用的是??re.findall("^(?!def\s+func\().*func\(", line1),執(zhí)行的結(jié)果將不會是預(yù)期的空列表,而是?[‘ def???func(‘],這是因?yàn)檫@種寫法,RE引擎將會嘗試搜索是否存在起始位置開始不是 "def\s+func\(" 而是 ".*func\(" 的字符串,但是line1中的"def"前面正好有一個空格,所以RE引擎發(fā)現(xiàn)從開始位置處搜索到的是帶一個前置空格的 "?def\s+func\(" 模式的字符串,而不是負(fù)向前表達(dá)式中沒有空格的 "def\s+func\(" 模式字符串,所以會匹配成功。
2、如果使用的是 re.findall("(?!.*def\s+func\().*func\(", line1),執(zhí)行的結(jié)果也不會是預(yù)期的空列表,而是 [ ‘ef???func(‘ ],這是因?yàn)槿绻鹥attern中沒有了^字符,就不是要求line1從開始就必須滿足匹配條件,而是line1中任意位置能夠滿足匹配條件都可以,所以line1中的 "ef???func(" 這個字符串就能滿足匹配條件
——?綜上所述,建議嘗試正則匹配“在xxx之前不出現(xiàn)yyy,且 xxx 和 yyy 之間可能存在其他不定長字符串”的場景時,優(yōu)先考慮使用負(fù)向前行斷言; 對于能夠確定xxx和yyy之間是定長的情況下,可以使用負(fù)向后行斷言
再例如考慮在line3中匹配 "func(" 字符串的時候,要求在 "func(" 前不能出現(xiàn)#符號,即要求func函數(shù)的調(diào)用語句沒有被注釋掉,因?yàn)?# 和 func( 之間的字符長度完全是隨機(jī)未知的,故應(yīng)該使用負(fù)向想前行斷言方式的 re.findall("^(?!.*#.*func\().*func\(", line3),而不是 re.findall("(?
原文:http://www.cnblogs.com/xaviercd/p/5818731.html
總結(jié)
以上是生活随笔為你收集整理的python 正则表达式 断言 不定长表达式_MyEssay 之 Python正则表达式 —— 四种断言扩展的理解...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 罕见!日本发现超2.5米长巨型深海鱼:全
- 下一篇: python判断语句入门教程_Pytho