從一則案例解析js正則的String對象的replace方法使用技巧

首先介紹一下業務需求:函數

在實時輸入過程當中,&&、||和-三個符號中的任意兩個(包括自身重複在內)不能直接或經過空格連在一塊兒,不然只保留第一個。測試

思路1:窮舉

這是我第一時間想到的方法,窮舉這三個符號任意兩個符號的排列組合,而後一一替換。根據排列組合公式可知一共有6種不一樣的組合方式,須要寫6個正則。
這種方法的好處是易於理解,但缺點也顯而易見,代碼臃腫,難以維護。ui

思路2:寫一個匹配出全部組合的正則,而後進行替換。

首先,寫出這個正則spa

let reg = /((&&|\|\||-)\s*){2,}/g
複製代碼

這個正則的意思是,匹配任意這三個符號(&& || -)加零個或多個空格出現兩次以上的文本。
有了這個正則,接下來就是如何替換了,首先想到的是正則的反向引用了$1($1的意思是第一個分組的內容,正則中括號()表明分組,即((&&|\|\||-)\s*)code

先來分析一下這個正則的匹配過程,咱們寫個測試案例來演示regexp

'|| -'.replace(/((&&|\|\||-)\s*){2,}/g,"\$1")   // -
複製代碼

匹配過程是這樣的:字符串

  • 從左到右遍歷這個字符串,找到 "|| "符合第一個分組內容,但不符合{2,}(出現兩次以上), 此時$1分組的內容是"|| "
  • 繼續遍歷,匹配到"-"符合規則,此時$1分組的內容是"-"
  • 這時已知足(&&|\|\||-)\s*)同時出現兩次以上的規則,開始替換,將整個字符串替換成$1,即-,因此輸出爲"-"

那麼問題來了,業務的需求是替換成第一個字符,而咱們卻替換成了最後一個字符。彆着急,先喝口水冷靜一下。其實咱們只要把原字符串翻轉一下,再傳進來不就符合要求了嗎,替換完畢後記得把字符串翻轉回去就好了string

// 翻轉字符串
function rever(str) { 
  return str.split("").reverse().join("")
}
複製代碼

完整代碼以下:it

let str = 'ccc && ||'
function rever(str) {
  return str.split("").reverse().join("")
}
let newStr = rever(rever(str).replace(/((&&|\|\||-)\s*){2,}/g,"\$1"))
console.log(newStr);
複製代碼

代碼寫出來了,測試結果也符合預期,那麼就大功告成了嗎?
看看這段代碼的實現原理,是把原字符串翻轉,而後進行匹配替換,替換完在把字符串翻轉回來。 代碼執行過程當中,是對原字符進行了修改的。若是放到生產環境中,因爲用戶的輸入習慣不一樣,可能會形成某些不可預期的錯誤。io

另闢蹊徑:

replace的第二個參數,除了傳入字符串,不是還能夠傳入一個函數嗎?咱們只要在這個函數中,把符合業務須要的第一個字符找出來,而後return 出去,不就完事了嗎?
用這種方式處理,不會污染原字符串,沒有反作用。不知道算不算得上最優解呢?
代碼很簡單,你們看一下應該就明白了:

let str = 'ccc && ||'
let newStr = str.replace(/((&&|\|\||-)\s+){2,}/g, function(a){
  return a.substr(0, a.indexOf(' ')) + ' ';
});
console.log(newStr);  // "ccc && "
複製代碼

PS:點個贊再走吧~

相關文章
相關標籤/搜索