Python正則表達式進階-零寬斷言


1. 什么是零寬斷言
  有時候在使用正則表達式做匹配的時候,我們希望匹配一個字符串,這個字符串的前面或后面需要是特定的內容,但我們又不想要前面或后面的這個特定的內容,這時候就需要零寬斷言的幫助了。所謂零寬斷言,簡單來說就是匹配一個位置,這個位置滿足某個正則,但是不納入匹配結果的,所以叫“零寬”,而且這個位置的前面或后面需要滿足某種正則。

2、不同的零寬斷言

  零寬斷言:正向反向兩類,每類又分為:預測先行回顧后發

  

  正預測先行:簡稱正向先行斷言,語法:(?=exp),它斷言此位置的后面能匹配表達式exp,但不包含此位置;
  如:a(?=\d),返回匹配字符串中以數字為結尾的a字符。

  正回顧后發:簡稱正向后發斷言,語法:(?<=exp),它斷言此位置的前面能匹配表達式exp;
  如:(?<=\d)a,返回匹配字符串中以數字為開頭的a字符。

  負預測先行:簡稱反向先行斷言,語法:(?!exp),它斷言此位置的后面不能匹配表達式exp;
  如:a(?!\d),返回不匹配字符串中以數字結尾的a字符。

  負回顧后發:簡稱反向后發斷言,語法:(?<!exp),它斷言此位置的前面不能匹配表達式exp;
  如:a(?<!exp)a,返回不匹配字符串中以數字開頭的a字符。

  

3、零寬斷言的實踐與總結

  示例:提取<div>Hello World</div>中Hello World

  目標字符串:Hello World

  根據以上所說,當我們需要提取字符串的時候,可以用斷言,思路如下:

  首先,目標字符串是hello world,那么它可以歸納為 .* 

  其次,目標字符串前面有<div>,既然是前面有,那么根據四種斷言的含義,容易得出用正向后發斷言(?<=exp),將它放在目標字符串前面,得到(?<=<div>).*,進一步可以將div歸納為[a-zA-Z]+,從而得到(?<=<[a-zA-Z]+>).*

  最后,目標字符串后面有</div>,既然是后面有,那么根據四種斷言的含義,容易得出用正向先行斷言(?=exp),將它放在目標字符串后面,從而得到(?<=<[a-zA-Z]+>).*(?=</[a-zA-Z]+>)

  進一步的,我們發現前后兩個斷言中都有[a-zA-Z]+,可以使用分組來避免書寫重復的內容:(?<=<([a-zA-Z]+)>).*(?=</\1>),當然也可以使用命名分組,這里就不展開了。

  說到這里,我歸納出了幾句書寫斷言的口訣:

    前面有,正向后發(?<=exp),放前面;

    后面有,正向先行(?=exp),放后面;

    前面無,反向后發(?<!exp),放前面;

    后面無,反向先行(?!exp),放后面。

  請記住,這個前面和后面是針對目標字符串,也就是你要提取出來的字符串而言的。

 

4、實戰:

  4.1、正向先行(?=exp):獲取字符串中以ing結尾的字符:

  

  4.2、正向后發(?<=exp):獲取字符串中以do開頭的單詞后半部分:

  

  4.3、反向先行(?!exp):匹配出字符串中不是以ing結尾的單詞:

   

  此處有雷,如果字符串變成“do  run going hing”你再試試看,此處有待解決。

  4.4、反向后發(?<!exp):匹配字符串中不以do開頭的單詞:

  

  此處有雷,同上

   總結:主要原因是因為反向斷言不支持匹配不定長的表達式;

   4.5、正向先行后發斷言結合應用:字符串時ip地址,獲取整數部分

  

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM