JavaScript正則表達式replace的一個坑

題圖來自://wallhaven.cc/w/md353k

經常聽大家說JavaScript是魔法語言,咱卻沒有什麼深刻體會。直到這回踩到這個坑,我終於醒悟了,JavaScript果然來自霍格沃茨!

trymagic_smaller-2021-11-06

0x00 踩到坑

昨天咱經過一番考慮後決定將 Python正則表達式細節小記 這篇筆記發到個人部落格上。選好文章音樂,複製markdown內容…發布!

按照慣例我檢查了一下發布後的文章內容,然後就見到了一個奇怪的現象:

issuehappens-2021-11-06

文章內容到一半的時候全被替換成 模板里的HTML 了…

之前調試部落格的時候從沒遇到過這個問題,我一時就有點摸不著頭腦( >﹏<。),但沒關係,比對一下原文檔就應該知道問題在哪了:

comparison-2021-11-06

很明顯能發現是從$開始被替換了,我心裡咯噔一下:怕不是和正則表達式有關!不過在排查正則表達式之前我去改了一下部落格後台部分的程式碼:

modifiedcode-2021-11-06

結果問題仍然存在,我接著還拿著這樣的內容片段進行復現,但沒能成功($並沒有被替換成其他內容):

test$

 $ 
test$

0x01 坑在哪

到最後,我還是懷疑回了正則表達式,但想來想去還是摸不著頭腦,正則表達式和用作替換的字元串有什麼關係,$不是用在正則表達式里的嗎?而且為什麼刻意用$去復現又不行呢?

baldscratch-2021-11-07

實在不行只能去求助一下某搜索引擎了:

googlesearch-2021-11-07

不查不知道,一查嚇一跳,看到有老哥提到了replace函數接收的字元串不僅僅是字元串,我趕緊去MDN查了一下:

syntaxofreplace-2021-11-07

原來用作替換的字元串內能包括一些特殊的變數名!

變數名 代表的值
$$ 插入一個 “$”。
$& 插入匹配的子串。
$` 插入當前匹配的子串左邊的內容。
$’ 插入當前匹配的子串右邊的內容。
$n 假如第一個參數是 RegExp對象,並且 n 是個小於100的非負整數,那麼插入第 n 個括弧匹配的字元串。提示:索引是從1開始。如果不存在第 n個分組,那麼將會把匹配到到內容替換為字面量。比如不存在第3個分組,就會用「$3」替換匹配到的內容。
$ 這裡Name 是一個分組名稱。如果在正則表達式中並不存在分組(或者沒有匹配),這個變數將被處理為空字元串。只有在支援命名分組捕獲的瀏覽器中才能使用。

表格原地址: //developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/replace#使用字元串作為參數

現在再回去看文章markdown內容,有一部分我是這樣寫的:

到了這裡,我發現老師說的在```[]```中**被當作普通字元**的元字元只是一部分罷了,主要是 ```*```,```?```,```+```,```{}```,```()```,```$``` 這些元字元。

毫無疑問其中的$\`就被替換為了匹配字串左邊的內容,也就是模板的前面一部分,才導致文章被處理成這樣。

可以說真的非常魔法了,萬萬沒想到JavaScript竟然在待替換字元串這裡內置了一些$變數名的用法。要是我沒有想著把這篇小記發到個人部落格上,說不定還得要好一陣子才能發現這個問題。

0x02 解決方法

解決方法其實很簡單,str.replace(regexp|substr, newSubStr|function)的第二個參數是可以接受一個函數的,而這個函數的 返回值 就被直接用作匹配項替換了,而不是先尋找一遍$變數名。

比如我原來是這樣寫的:

str.replace(new RegExp('\\{\\[' + from + '\\]\\}','gi'), to);

那麼我用箭頭函數改寫一下就行了:

str.replace(new RegExp('\\{\\[' + from + '\\]\\}','gi'), ()=>to);

其實就相當於:

str.replace(new RegExp('\\{\\[' + from + '\\]\\}','gi'), function(){
    return to;
});

關於這個函數傳入的參數可以看MDN文檔這裡的 指定一個函數作為參數

usefuncasarg-2021-11-07

0x03 教訓

以後寫JavaScript程式碼的時候還是不能掉以輕心了,說不定在哪個角落還有我不太清楚的魔法。遇到不會或者不清楚的一定要多查文檔,不然一旦寫進項目里可能就會成為一個遺留的潛在問題。(ノへ ̄、)