作者 | 徐小夕來源 | 趣談前端
熟悉我的朋友可能會知道,我一向是不寫熱點的。為什么不寫呢?是因為我不關注熱點嗎?其實也不是。有些事件我還是很關注的,也確實有不少想法和觀點。但我一直奉行一個原則,就是:要做有生命力的內容。
對于前端工程師來說,正則表達式也許是javascript語言中最晦澀難懂的,但是也往往是最簡潔的。工作中遇到的很多問題,諸如搜索、查找、高亮關鍵字等,都可以使用正則輕松解決,所以有句話說的好:
今天筆者就復盤一下javascript正則表達式的一些使用技巧和高級API,并通過幾個實際的案例,來展現正則表達式的魅力。如果大家覺得正則表達式理解起來很麻煩,也可以使用如下在線網站,只需要輸入你的正則表達式,它就能以圖形的方式將你的正則展示出來:
你將收獲:
正文
對于正則的基本用法筆者這里就不總結了,這里重點介紹一些比較有用且難懂的知識點。在最后筆者會寫10個經典的正則案例,供大家學習參考,或者在工作中直接使用。模式匹配的用法(x)
案例:
let str = 'xuxi is xuxi is'
let reg = /(xuxi) (is) \1 \2/g
reg.test(str)
str.replace(reg, '$1 $2')
解釋: 其中括號被稱為捕獲括號,模式中的 \1 和 \2 表示第一個和第二個被捕獲括號匹配的子字符串,即 xuxi 和 is,匹配了原字符串中的后兩個單詞,因此(1)中運行的結果為true。當我們在字符串中使用replace時,我們可以使用$1,$2這樣的方式獲取第n個匹配項,并用來替換字符串,如(2)中的運行結果。
非捕獲括號的模式匹配(?:x)
let str = 'xuxixuxi'
let reg = /(?:xuxi){1,2}/g
reg.test(str)
解釋:其中(?:)被稱為非捕獲括號,我們可以使用它匹配一組字符但是并不記住該字符,一般用來判斷某類字符是否存在于某字符串中。
先行斷言x(?=y)
let str = '王者融化'
let reg = /王(?=者)/
reg.test(str)
解釋: /王(?=者)/會匹配到"王"僅當它后面跟著"者",但是"者"不屬于匹配結果的一部分。
后行斷言(?<=y)x
let str = 'xuxiA'
let reg = /(?<=xuxi)A/
reg.test(str)
解釋:/(?<=xuxi)A/會匹配到A僅當它前面為xuxi,但是xuxi不屬于匹配結果的一部分。正向否定查找x(?!y)
正向否定查找:僅僅當'x'后面不跟著'y'時匹配'x'。
案例:
let str = '3.1415'
let reg = /\d+(?!\.)/
reg.exec(str)
解釋:其中/\d+(?!.)/匹配一個或多個數字,當且僅當它后面沒有小數點時,所以(1)中執(zhí)行后會匹配到1415而不是3.1415
反向否定查找(?<!y)x
反向否定查找:僅僅當'x'前面不是'y'時匹配'x'。
let str = '3.1415'
let reg = /(?<!\.)\d+/
reg.exec(str)
解釋:/(?<!.)\d+/匹配一個數字,當且僅當前面字符不是.時,此時將匹配3。
字符集合和反向字符集合的用法 [xyz] / [^xyz]
[xyz]:一個字符集合。匹配方括號中的任意字符,包括轉義序列。你可以使用破折號(-)來指定一個字符范圍。
[^xyz]:一個反向字符集。也就是說,它匹配任何沒有包含在方括號中的字符。你可以使用破折號(-)來指定一個字符范圍,任何普通字符在這里都是起作用的。
let str = 'abcd'
let reg1 = /[a-c]+/
let reg2 = /[^d]$/
reg1.test(str) //true(1)
reg2.test(str) //false(2)
解釋:(1)中將返回true因為字符串中包含a-c中的字符,(2)中獎返回false,因為字符串結尾為d,但正則reg2需要匹配結尾不為d的字符串。
詞邊界和非單詞邊界匹配\b\B
\b 匹配一個詞的邊界。一個詞的邊界就是一個詞不被另外一個“字”字符跟隨的位置或者前面跟其他“字”字符的位置,例如在字母和空格之間。注意,匹配中不包括匹配的字邊界。換句話說,一個匹配的詞的邊界的內容的長度是0。
\B 匹配一個非單詞邊界。匹配如下幾種情況:(1)字符串第一個字符為非“字”字符 (2)字符串最后一個字符為非“字”字符 (3)兩個單詞字符之間 (4)兩個非單詞字符之間 (5)空字符串
let str = 'xuxi'
let reg1 = /xi\b/
let reg2 = /xu\B/
reg1.exec(str) //[xi](1)
reg2.exec(str) //[xu](2)
解釋: (1)中匹配到了單詞邊界,即xi,為該字符串的末尾;(2)中應為xu為非單詞邊界,所以會被其匹配到。
空白字符/非空白字符匹配\s\S
\s:匹配一個空白字符,包括空格、制表符、換頁符和換行符。
let str = 'xuxi is'
let reg1 = /.*\s/g
let reg2 = /\S\w*/g
reg1.exec(str) //[xuxi](1)
reg2.exec(str) //[xuxi](2)
解釋:(1)和(2)中執(zhí)行之后都將匹配xuxi,一個是空白字符之前的匹配,一個是非空白字符的匹配。
單字字符/非單字字符匹配\w/W
\w: 匹配一個單字字符(字母、數字或者下劃線)。等價于 [A-Za-z0-9_]
\W: 匹配一個非單字字符。等價于 [^A-Za-z0-9_]
正則10大應用案例
接下來筆者將總結幾個使用正則的實際應用,供大家學習和參考。1. 去除字符串內指定元素的標簽
function trimTag(tagName, htmlStr) {
let reg = new RegExp(`<${tagName}(\\s.*)*>(\\n|.)*<\\/${tagName}>`, "g")
return htmlStr.replace(reg, '')
}
2. 短橫線命名轉駝峰命名
// 短橫線轉駝峰命名, flag = 0為小駝峰, 1為大駝峰
function toCamelCase(str, flag = 0) {
if(flag) {
return str[0].toUpperCase() + str.slice(1).replace(/-(\w)/g, ($0, $1) => $1.toUpperCase())
}else {
return str.replace(/-(\w)/g, ($0, $1) => $1.toUpperCase())
}
}
3. 實現一個簡單的模板引擎
關于實現一個模板引擎,實現中用到了大量的正則,建議感興趣的可以直接看實現一個簡單的模板引擎。4. 去除字符串中的空格符
function trimAll(str) {
return str.replace(/\s*/g,"")
}
5. 判斷指定格式的數據輸入合法性
function numCheck(str, specialNum) {
if(str.indexOf(',') > -1) {
return str.splite(',').every(item=>this.numCheck(item));
} else {
return str.split(specialNum).length === 2;
}
}
6. 去除url參數字符串中值為空的字段
// 去除url參數字符串中值為空的字段
const trimParmas = (parmaStr:string = '') => {
return parmaStr.replace(/((\w*?)=&|(&\w*?=)$)/g, '')
}
7. 將瀏覽器參數字符串轉化為參數對象
function unParams(params = '?a=1&b=2&c=3') {
let obj = {}
params && params.replace(/((\w*)=([\.a-z0-9A-Z]*)?)?/g, (m,a,b,c) => {
if(b || c) obj[b] = c
})
return obj
}
8. 計算字符串字節(jié)數
/**
* 計算字符串字節(jié)數
* @param str
* @desc 一個中文占2個字節(jié), 一個英文占一個字節(jié)
*/
function computeStringByte(str) {
let size = 0,
strArr = str.split(''),
reg = /[\u4e00-\u9fa5]/ // 判斷是否為中文
for(let i = strArr.length; i--; i>=0) {
if(reg.test(strArr[i])) {
size+= 2
}else {
size += 1
}
}
return size
}
9. 匹配是否包含中文字符
function hasCn(str) {
let reg = /[\u4e00-\u9fa5]/g
return reg.test(str)
}
10. 實現搜索聯想功能
function searchLink(keyword) {
// 模擬后端返回數據
let list = ['abc', 'ab', 'a', 'bcd', 'edf', 'abd'];
let reg = new RegExp(keyword, 'i');
return list.filter(item => reg.test(item))
}
該文章在 2023/5/19 15:24:42 編輯過