正則表達式位數和零寬斷言

正則表達式位數和零寬斷言

之前的文章裏,已經給大家展示了正則的匹配流程,希望大家能夠好好回顧下。https://segmentfault.com/a/11...
下面我們主要討論兩部分的內容:1. 正則表達式的位數,2. 零寬斷言


正則表達式的位數

在有需要正則表達式,很常見的操作就百度一下。看能不能找到滿足我需求的。有時候你會找到的,比如手機校驗,密碼校驗,郵箱校驗。但是很多人往往都看不懂網上的正則的意思。這個就是學習正則的一個誤區。
在我看來,我們學習正則應該是:瞭解其匹配過程,再看懂正則表達式,最後纔是自己寫正則表達式。
下面主要講的就是怎麼看懂正則表達式。而看懂正則表達式的關鍵--表達式匹配的字符位數。
我們拿例子來說吧。

// 第一個例子,表達式匹配4個字符,一個“非語法關鍵字”的字符會佔一位。
var reg1 = /abcd/;

// 第一個例子, 表達式匹配了5個字符(先是ab,再是abc裏的任意一個,接着是cd)。說明下:[]範圍內的內容能佔一位,不管裏面放了多少東西都是或的意思。
var reg2 = /ab[abc]cd/;

// 第三個例子, 匹配了5個或以上(先是ab,再是abc裏的任意一個,接着是c,最後是一個d或者很多個d),這類的功能類似的*,{1,5}
var reg3 = /ab[abc]cd+/;

// 第四個例子,匹配4個(三個字符abd,和一個[])。  像^, $這類的標示位置的語法是不會佔一個字符的,只是對位置的一些要求。
var reg4 = /^ab[abc]d$/

// 第五個例子(這個是個真實例子,不知道大家能否快速看清),匹配無數字符(首選匹配##item#七個字符,接着匹配任意字符的任意個,接着匹配字符#item##)
// 這個裏面的?是不要貪婪模式,其實這裏說是遇到第一個#item##。關於貪婪模式,希望大家自己查閱下。
var reg5 = /((##item#)([\w|\W])+?(#item##))/

我是通過例子,想盡量說的直白點,讓大家更容易理解。我這裏面的例子並沒有列全情況,如果大家有什麼不理解的正則,不確定裏面匹配多少位數,歡迎在下面留言,我看到就會給大家解答。
下面我們說說零寬斷言


零寬斷言

在說清楚零寬斷言,我們需要簡單介紹下爲啥會有這個。它的存在是爲了解決什麼問題呢?
這個存在是解決我們一些特定的要求,且不需要展佔位數。比如:字符串的開頭和結尾用"#"替換(/^|$/, 需要找到開頭和結尾,又沒有真實字符),數字字符串每隔三位添加一個逗號,字符串裏b的後面不能是數字等等,這些都是對位置的條件,但這些條件本身又沒有佔位。

表示位置,又不佔字符的語法總共就這些:^ $ \b \B (?=) (?!)
^(脫字符)匹配開頭,在多行匹配中匹配行開頭。
$(美元符號)匹配結尾,在多行匹配中匹配行結尾。
b是單詞邊界,具體就是w和W之間的位置,也包括w和^之間的位置,也包括w和$之間的位置。
B就是b的反面的意思,非單詞邊界。例如在字符串中所有位置中,扣掉b,剩下的都是B的。
以上4個比較簡單,尤其是^ 和$,這裏就不多說了。下面主要說說這兩個(?=)和(?!)
(?= P)表示的此刻位置後面應該是P模式,這個模式不單單是字符,也可能是複雜正則。比如(?= l),(?= [abc]ede), (?= \d +)
(?!p) 表示的此刻位置後面應該是P模式的以外的位置,和上一個正好相反。
舉幾個例子幫助理解下

// 第一個例子, 正則的表達式,要求在cate後位置的後面應該是一個數字。再之後應該是數字位,再之後是ok。\d是不能少的,也很好的說明了(?=)是不佔位。
var reg6 = /cate(?=\d)\dok/
var str = 'cate3ok'
str.match(reg6); // cate3ok

// 第二個例子,如果我們想在##p#和#p##之前的字符串裏有ok字符這段字符串。
var reg7 = /##p#(?=.*ok).*#p##/
var str1 = '##p#fsdfsdokdfsdfs#p##'
reg7.test(str1);

// 第三個例子,如果我們想在##p#和#p##之前的字符串裏有ok字符這段字符串。如果字符串裏有兩段##p#怎麼辦呢?
var reg7 = /##p#(?=.*ok).*#p##/
var str1 = '##p#fsokfs#p####p#fsfs#p##'
str1.match(reg7) // ##p#fsokfs#p####p#fsfs#p##   這個結果就不是我們想要的了。不知大家能否想明白?

// 我們把正則改下
var reg8 = /##p#(?=.*ok).*?#p##/
str1.match(reg8) //##p#fsokfs#p##
// 好像是對了哦,但是我們把字符串改下, 兩段##p#換個位置
var str2 = '##p#fsfs#p####p#fsokfs#p##';
str2.match(reg8) // ##p#fsfs#p##  又不對了。 這個地方不知能否想明白。

// 我們再把正則改下
var reg9 = /##p#(?=(.(?!#p##))*ok).*?#p##/;
str2.match(reg9); // ##p#fsokfs#p##  這次就對上了。

我想對最後的正則進行解釋下。 首選是?#p## 這個地方的?是告訴正則我不用貪婪模式,(?=(.(?!#p##)).*ok).* 這部分裏我們先不看裏面的?部分,把它當成P(?=p.*ok).*, 這部分意思,我們需要任意字符,在任意字符的後面任意位置應該出現一個OK。最後裏面的?部分,其實也是對這個任意字符的條件,要求任意字符後面不能是#p##字符串。這樣就實現了啦。

我知道這個可能很難理解清楚,希望大家還是多看看,多想想。如果有問題,還是歡迎下面留言。

clipboard.png

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章