寫於2015年5月7日,可能已過時,請謹慎參考。
好久沒更新內容了,今天分享一個小的知識點,一個正規表示式方面的很容易被人忽視的坑。
我們知道,正規表示式中,可以用 .
表示任意單個字元,但在 underscore 和 jquery 的原始碼中,我們可以看到,這些著名類庫的程式碼中,經常並不是用 .
來表示任意字元,而是使用 [wW]
或者 [sS]
。乍一看,好像表達的含義是一樣的,可是為什麼放著簡單的方法不用,而去多繞個圈子?今天就簡單說說這個問題。
首先我們必須要正確理解 .
的含義。其實說它表示任意單個字元,可能會讓人產生誤解,必須要強調一下,這個“任意單個字元”不包括控制換行的字元,也就是不包含
、
、
u2028
或 u2029
這幾個字元。而 W
和 s
中是能夠包含這些字元的。那個這兩種寫法的差異也就很清晰了,就是能否匹配到幾個換行控制符的差異。
那麼在什麼時候我們需要考慮這幾個換行控制符呢?當要處理的字串可能包含換行時。這樣的情景太多了,處理 html 字串、處理 template、Node.js 讀取文字等等。
提及多行文字的場景,我們很容易想到正規表示式的 m
模式(多行模式)。那麼多行模式對我們今天討論的問題有影響嗎?我不是很確定。為什麼不確定呢?有些人信誓旦旦地聲稱單行模式下 .
的含義與多行模式下不同,單選模式下等同於 [wW]
或者 [sS]
,而多行模式下會排除換行控制符。但據我試驗,以及參考 MDN 的說法,這是不對的。的確有很多語言的正規表示式會有上述特性,但在 javascript 中我沒有看到,不知道會不會有瀏覽器方面的差異。那麼多行模式對於 javascript 而言影響的是什麼呢?我認為僅僅是改變了 ^
和 $
標識的含義:單行模式下,分別表示整個字串的開始的結尾;多行模式下表示每一行的開始和結尾。而不管多行模式還是單行模式,我認為 .
都是不包含換行控制字元的,等價於 [^
u2028u2029]。
再多延伸一點點,對於現代瀏覽器,可以直接用 [^]
來匹配任意字元的。
例子程式不想寫了,有興趣的可以自己試驗一下,分別用 /.*/g
、/^.*$/g
、/.*/gm
、/^.*$/gm
來匹配一下 "abc
,其中道理不言自明。
edf"
2018年3月16日補充:
感謝 Will_Liu 提醒,ECMAScript中正則增加 dotAll(s
) 的標識的提案已經在 stage 4 了。詳情請參考:proposal-regexp-dotall-flag。
如果使用 babel,可以新增 @babel/plugin-transform-dotall-regex 開啟這個特性。
示例 .babelrc:
{
"plugins": ["@babel/plugin-transform-dotall-regex"]
}
複製程式碼