壹 ❀ 引html
我在從零開始學正則(一)這篇文章中介紹了正則橫向模糊與縱向模糊匹配模式,以及經常使用的字符組與量詞,掌握了這些其實已經算正則入門了。在文尾留下了兩個正則問題,請寫出匹配24小時制時間與16進制顏色的正則,在學習第二章以前咱們先搞定這兩個問題。git
24小時制時間格式通常是09:30這樣,小時的第一位數字多是[0-2]三種狀況之一,當爲0,1時,第二位數字能夠是[0-9]任意數字,當爲2時第二位數字只能是0-3之間的數字。第三位數字只能是0-5之間的數字,最後一位數字只能是0-9之間。github
咱們只用對於小時的兩種狀況作個分支,因此正則能夠寫成這樣:數組
var regex = /^([01][0-9]|[2][0-3]):[0-5][0-9]$/; regex.test("00:07"); //true regex.test("23:59"); //true
注意,匹配小時的分支咱們使用了一對圓括號包裹,表示這是一個組,而組內包含了兩個分支狀況,若是不加圓括號正則解析時會將管道符 | 左右兩側理解成兩個分支,以下圖,很明顯這不是咱們想要的規則:學習
其次,在正則內部開頭和結尾咱們分別使用了^$兩個符號,這表示正則匹配時嚴格以字符串開頭和結尾中間的內容爲匹配對象,若是不加效果就是這樣:測試
var regex = /([01][0-9]|[2][0-3]):[0-5][0-9]/; regex.test("0000:0709");//true
這裏是由於字符串中間有一部分是符合規則的,所以仍是符合匹配規則,因此若是咱們想匹配一個字段從頭至尾是否符合規則,必定得記得加上^$符號。spa
咱們再來分析16進制顏色,老實說我還真不知道16進制顏色範圍是多少,查了下,每一個字母範圍均爲[0-9a-fA-F],但因爲顏色值能夠簡寫,好比 #ffffff 能夠簡寫成 #fff,因此存在6位與3位的狀況,正則能夠這麼寫:設計
var regex = /^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/; regex.test("#e4393c"); //true regex.test("#2b99ff"); //true
那麼上章節留下的問題就說到這,開始第二章學習。說在前面,正則學習系列文章均爲我閱讀 老姚《JavaScript正則迷你書》的讀書筆記,文中全部正則圖解均使用regulex製做。本章節主要講述如何匹配字符位置,那麼本文開始!3d
貳 ❀ 正則中的位置code
注意,這裏所說的位置並非咱們遍歷數組時所使用的索引概念,正則匹配的位置又稱爲錨,是指相鄰字符之間的位置,這裏借用原書中的圖解,每一個箭頭就是一個位置:
正則使用中,匹配位置的字符又稱爲錨,在文章開頭咱們已經見過了 ^$ 兩個錨,咱們來驗證下位置的概念,看個簡單的例子:
var str = '聽風是風'; var regex = /^|$/g; var result = str.replace(regex, '❀'); //❀聽風是風❀
能夠看到兩個位置被替換成了花朵,此時字符串的開頭位置與結尾位置發生了變化,開頭變成了花朵左邊,結尾位置變爲第二朵花的右邊。
叄 ❀ 理解正則的錨
出了經常使用的^$,在ES5中一共包含六個錨,分別是^、$、\b、\B、(?=p)、(?!p),咱們一一細說。
^ 脫字符:匹配開頭,在多行中匹配行開頭,好比:
var str = '聽風\n是風'; var regex = /^/mg; var result = str.replace(regex, '❀');
注意,正則結尾添加了一個mg,g(global)前面有解釋表示全局匹配,表示一行從左到右完整匹配一遍,而m(more)表示多行匹配,mg就是多行全局匹配,每行無論文本多長,都徹底匹配一遍。
$美圓符號:匹配結尾,在多行中匹配行尾。
\b單詞邊界:表示\w(單詞字符)與\W(非單詞字符)之間,\w(單詞字符)與 ^ (脫字符)之間,以及\w (單詞字符)與$ 之間的位置,有點難理解,先看個例子:
var str = '[echo].123'; var regex = /\b/g; var result = str.replace(regex, '❀'); //[❀echo❀].❀123❀
上面解析有點長,咱們縮短點,\b表示\w與\W、^、$之間的位置,而\w範圍是[0-9a-zA-Z_],那麼咱們再看上面的例子,爲了方便理解,咱們拆分細說:
從左往右看,首先 ^ 與 [ 之間不知足,再到 [ 與 e 之間,[ 是非單詞符而 e 是單詞符,知足條件。
echo因爲四個字母都是單詞符,直接跳過,o 與 ] 又知足了條件。
] 與 . 之間很明顯不符合,再看 . 與1又知足了條件。
123都是單詞符,跳過,直接到了尾部 3 與 $,知足條件。
\B非單詞邊界,意思與\b相反,匹配\w 與 \w、 \W 與 \W、^ 與 \W,\W 與 $ 之間的位置,仍是上面的例子,咱們改改匹配條件:
var str = '[echo].123'; var regex = /\B/g; var result = str.replace(regex, '❀'); //❀[e❀c❀h❀o]❀.1❀2❀3
能夠看到 ^ 與 [ 之間,以及單詞符與單詞符之間都知足了條件。
(?=p)正向先行斷言:p表示一個匹配模式,即匹配全部知足條件p的字段的前面位置,有點繞口,看個簡單的例子:
var str = 'hello'; var regex = /(?=l)/g; var result = "hello".replace(regex, '❀'); //he❀l❀lo
這裏就是先在字符串中找到字母 l,而後再找到 l 前面的位置就是目標位置。爲了方便,直接利用前面位置理解的圖,也就是這兩個紅框了:
那麼(?!p)與(?=p)就是反過來的表示負向先行斷言,仍是上面的例子,咱們改改條件,也就是下圖中綠框中的位置:
var str = 'hello'; var regex = /(?!l)/g; var result = "hello".replace(regex, '❀'); //❀h❀ell❀o❀
若是不看這個圖,我不知道你們有沒有這樣的疑惑,不對啊,前面解釋 \b單詞邊界時,是從 ^脫字符 開始判斷的,脫字符也不知足條件前面也應該加朵❀,最終輸出難道不該該是 ❀❀h❀ell❀o❀ 這樣嗎?o後面有❀ 是由於o後面還有個 $,$不知足條件因此才這樣啊。
記住,^和$是兩個位置,^$是兩個位置,^$是兩個位置,不要將^$主動理解成兩個隱藏字符,咱們如今是在匹配位置。
因此 /(?=l)/g 就是在找 l 前面的位置,而 /(?!l)/g 本質上來講就是找不是字母 l 前面的其它全部位置!
那爲何 \b單詞邊界還能從 ^ 開始判斷呢,由於概念就包含了判斷\w 與 ^ 之間的位置,在判斷單詞邊界時,^$這兩個特殊位置就像兩個隱藏字符同樣,也成了判斷位置的條件(用位置判斷位置,騷的不行)。而在判斷(?!p)與(?=p)時,主要p不是^$,那麼此時的 ^$ 單純做爲兩個位置,不會主動做爲判斷條件參與判斷,這一點千萬不要弄混了!!!
肆 ❀ 位置的特性
讀到這裏我也有點迷糊,原本就是找位置,你 ^$ 做爲位置應該是被找的對象,怎麼還反客爲主成了找位置的條件了,位置和位置之間難道還有位置?正則裏還真是這樣!
咱們能夠將位置理解成一個空字符" ",就像上圖的箭頭,一個hello能夠寫成這樣:
"hello" = "" + "h" + "" + "e" + "" + "l" + "" + "l" + "" + "o" + "";
它甚至還能寫成這樣,站在位置的角度,位置能是無限個:
"hello" = "" + "" + "hello"
以正則的角度,咱們測試一個單詞是否爲hello甚至能夠寫成這樣:
var str = 'hello'; var regex = /^^^^^hello$$$$$$$$$$$$/g; var result = regex.test(str); //true
固然這是咱們站在匹配正則位置的角度抽象理解成這樣的,畢竟真的給字符串加空格,字符串就真的變樣了。
我也不太理解這個位置概念爲啥要設計成這樣....腦袋疼,反正你們理解這個點就行了。
\b單詞邊界會拿^$這兩個特殊位置做爲判斷其它位置的條件,記住這一點。
伍 ❀ 總
那麼到這裏,第二章就說完了,內容其實真很少,只是這個位置讓人有點懵,多回顧一下就行了。這裏我整理了一份簡單的思惟導圖,你們能夠看着回顧一下本篇知識點:
最後留幾個思考題,請寫出一個正則將"12345678"變成千位分隔符表示法 "12,345,678",以及寫一個正則驗證密碼,密碼格式必須在6-12位之間,且至少包含數字,小寫字符,大寫字符其中兩種。
那麼本文就到這裏了,我得學習第三章了!