JavaScript 中的前瞻斷言(lookahead)和后瞻斷言(lookbehind)相信用過的小伙伴就知道它的威力了,在一些特定的需求場景下,可以做到四兩撥千斤的作用,今天讓我們來盤點一下在 JavaScript 正則表達式中這兩個秘密武器吧。
前瞻斷言和后瞻斷言,在其他語言的正則表達式中也存在,這個特性不是 JavaScript 的專屬
概念定義
不管是前瞻斷言還是后瞻斷言,最終目的都是尋找在指定的模式(pattern)下,這個指定模式(pattern)下前面或者后面的字符子串, 得到的結果永遠是這些 前面或者后面的字符子串 而不是這個指定的模式(pattern)本身
前瞻或后瞻在匹配的時候不會實際匹配和捕獲字符,只是檢查某個位置前后是否符合指定條件,并不會改變正則的 lastIndex,在檢查完之后,正則表達式的其他部分繼續進行匹配。
前瞻斷言
在中文互聯網上 lookahead 被翻譯成 前瞻斷言、先行斷言等
前瞻斷言,是用于在檢查后面的子串是否匹配某個模式, 前瞻斷言包括正向前瞻和負向前瞻斷言。
- 正向前瞻:
X(?=pattern)
,如果 X 后面的子串符合pattern
模式, 就匹配 X。 - 負向前瞻:
X(?!pattern)
, 如果 X 后面的子串不符合pattern
模式, 就匹配 X。
后瞻斷言
在中文互聯網上 lookahead 被翻譯成 后瞻斷言、后行斷言等
后瞻斷言,是用于在檢查前面的子串是否匹配某個模式, 后瞻斷言包括正向后瞻斷言和負向后瞻斷言。
- 正向后瞻:
(?<=pattern)X
,匹配 X 前面滿足pattern
的子串。 - 負向后瞻:
(?<!pattern)X
,匹配 X 前面不滿足pattern
的子串。
這里有點需要注意的是 前瞻斷言是檢查后面的子串是否匹配,后瞻斷言是檢查前面的子串是否匹配。
這個規則感覺就是主打一個叛逆…
直接上代碼
前瞻斷言
- 正向前瞻
利用正向前瞻實現金額字符串格式化為帶有千分位分隔符的格式。 例如 12345
, 轉化為 12,345
解釋一下上述的正則表達式:
\B
:匹配非單詞邊界。確保逗號不會被添加在開頭(?=(\d{3})+(?!\d))
:匹配符合右側有一個或多個三位數字,且這些三位數字不是字符串的結尾。
這個正則同時使用了正向前瞻和負向前瞻。剛開始可能比較繞,可以看看下面的可視化原理慢慢消化一下
通過上述正則匹配到的結果,再使用 replace
方法用來替換為逗號, 即可實現金額的千分位
- 負向前瞻
我們可以用負向前瞻來過濾一些不符合條件的字符子串。例如下面我們需要匹配出不是金額的數字。
/\d+\b(?!元)/g
正則語法的意思是 “搜索 字符中的數字,但前提是后面沒有 元 這個字符”。
\b
是用于匹配一個單詞的邊界。這里使用 \b 就是為了匹配完整的數字。不然上面的測試用例里面的15
中 的數字1
也符合屬于數字,而且1
后面也沒有跟 元 這個字符單詞邊界指的是在單詞字符(字母、數字或下劃線)和非單詞字符(如空格、標點符號或其他字符)之間的位置,同時字符串的開頭或結尾也存在單詞的邊界。
后瞻斷言
- 正向后瞻
正向后瞻是如果當前匹配項前面有特定的匹配子串的話,當前匹配項就會被匹配,否則就跳過。
這里匹配 $
后面的金額, 我們可以用正向后瞻斷言去匹配出來。只有這個數字前面的內容滿足 $
就會匹配上,并返回到最終的結果中去。
- 負向后瞻
如果你剛看完上面的正向后瞻的示例代碼,此時你想在上面的基礎上,只匹配金額前面只有一個$
的, 這時候我們就可以用負向后瞻去做進一步約束。
這里使用 負向后瞻并不是最優解,這里只是為了做代碼演示構造的場景。
可以從可視化正則里面看出,負向后瞻就是只要當前匹配項前面不是 $$
的時候,才進行匹配,所以 $$34
就會被忽略掉
不過為了應用這個例子,我這里是故意這樣處理的,實際上為了滿足只匹配一個 $
的金額數字的話,我們可以直接在上面的 正則加上 \s
即可, 即: /(?<=\s\$)\d+/g
兼容性
前瞻斷言的兼容性是最好的,基本上是全綠的狀態,直接無腦沖就行了。
當我查caniuse 的時候,有被震驚到,第一次遇到這種兼容性這么好特性。要是前端所有的標準屬性有這兼容性就好了,好了,有點扯遠了哈。
后瞻斷言的兼容性差一些,除了在 Safari 瀏覽器中兼容性稍微差點,其他的都支持度很不錯。
小結
相信通過上面的介紹,你已經掌握了使用 前瞻斷言和后瞻斷言的精髓了,相信我使用它可以讓你寫正則的速度嗖嗖的,下班早早的。
如果這篇文章對你有幫助,歡迎點贊👍、關注?、轉發 ? !