首先介紹一下業務需求:
在實時輸入過程中,&&、||和-三個符號中的任意兩個(包括自身重複在內)不能直接或通過空格連在一起,否則只保留第一個。
思路1:窮舉
這是我第一時間想到的方法,窮舉這三個符號任意兩個符號的排列組合,然後一一替換。根據排列組合公式可知一共有6種不同的組合方式,需要寫6個正則。
這種方法的好處是易於理解,但缺點也顯而易見,程式碼臃腫,難以維護。
思路2:寫一個匹配出所有組合的正則,然後進行替換。
首先,寫出這個正則
let reg = /((&&|\|\||-)\s*){2,}/g
複製程式碼
這個正則的意思是,匹配任意這三個符號(&& || -)加零個或多個空格出現兩次以上的文字。
有了這個正則,接下來就是如何替換了,首先想到的是正則的反向引用了$1($1的意思是第一個分組的內容,正則中括號()代表分組,即((&&|\|\||-)\s*)
)
先來分析一下這個正則的匹配過程,我們寫個測試案例來演示
'|| -'.replace(/((&&|\|\||-)\s*){2,}/g,"\$1") // -
複製程式碼
匹配過程是這樣的:
- 從左到右遍歷這個字串,找到
"|| "
符合第一個分組內容,但不符合{2,}
(出現兩次以上), 此時$1分組的內容是"|| "
- 繼續遍歷,匹配到
"-"
符合規則,此時$1分組的內容是"-"
- 這時已滿足
(&&|\|\||-)\s*)
同時出現兩次以上的規則,開始替換,將整個字串替換成$1
,即-
,所以輸出為"-"
那麼問題來了,業務的需求是替換成第一個字元,而我們卻替換成了最後一個字元。彆著急,先喝口水冷靜一下。其實我們只要把原字串翻轉一下,再傳進來不就符合要求了嗎,替換完畢後記得把字串翻轉回去就行了
// 翻轉字串
function rever(str) {
return str.split("").reverse().join("")
}
複製程式碼
完整程式碼如下:
let str = 'ccc && ||'
function rever(str) {
return str.split("").reverse().join("")
}
let newStr = rever(rever(str).replace(/((&&|\|\||-)\s*){2,}/g,"\$1"))
console.log(newStr);
複製程式碼
程式碼寫出來了,測試結果也符合預期,那麼就大功告成了嗎?
看看這段程式碼的實現原理,是把原字串翻轉,然後進行匹配替換,替換完在把字串翻轉回來。
程式碼執行過程中,是對原字元進行了修改的。如果放到生產環境中,由於使用者的輸入習慣不同,可能會造成某些不可預期的錯誤。
另闢蹊徑:
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:點個贊再走吧~