正則表達(dá)式是用于匹配字符串中字符組合的模式。在 JavaScript 中休弃,正則表達(dá)式也是對(duì)象。這些模式被用于 RegExp 的 exec
和 test
方法, 以及 String 的 match
、matchAll
怔球、replace
、search
和 split
方法浮还。正則表達(dá)式的掌握程度能粗略地看出程序員的技術(shù)底子竟坛,所以技術(shù)面試、編程競(jìng)賽等 都特別喜歡考察正則表達(dá)式钧舌。本篇就帶你一起夯實(shí)一下 JavaScript 正則表達(dá)式的一些使用技巧:
創(chuàng)建正則表達(dá)式
在 JavaScript 的世界担汤,創(chuàng)建正則表達(dá)式有2個(gè)方法:
(1)使用一個(gè)正則表達(dá)式字面量,其由包含在斜杠之間的模式組成洼冻。比如 :
const reg = /ab+c/
(2)調(diào)用RegExp對(duì)象的構(gòu)造函數(shù)崭歧。比如:
const reg = new RegExp("ab+c")
注意:以上2個(gè)方法雖然都能創(chuàng)建正則表達(dá)式,但是還是有區(qū)別的:
(1)使用第一個(gè)方法撞牢,在腳本加載后正則表達(dá)式字面量就會(huì)被編譯率碾。當(dāng)正則表達(dá)式保持不變時(shí)叔营,使用此方法可獲得更好的性能。
(2)使用第二個(gè)方法所宰,在腳本運(yùn)行過(guò)程中用構(gòu)造函數(shù)創(chuàng)建的正則表達(dá)式會(huì)被編譯绒尊。如果正則表達(dá)式將會(huì)改變,或者它將會(huì)從用戶輸入等來(lái)源中動(dòng)態(tài)地產(chǎn)生仔粥,就需要使用構(gòu)造函數(shù)來(lái)創(chuàng)建正則表達(dá)式婴谱。
當(dāng)然,這樣表述可能不太深刻件炉,下面找一道面試題帶你實(shí)踐一下勘究。
經(jīng)典面試題 "Word Finder"
題目要求:
使用一個(gè)方法來(lái)擴(kuò)展字典,該方法返回與模式匹配的單詞列表斟冕。這個(gè)模式可以包含字母(小寫)和占位符("?")口糕。占位符只代表一個(gè)任意的字母,比如:
const fruits = new Dictionary(['banana', 'apple', 'papaya', 'cherry']);
fruits.getMatchingWords('lemon'); // must return []
fruits.getMatchingWords('cherr??'); // must return []
fruits.getMatchingWords('?a?a?a'); // must return ['banana', 'papaya']
fruits.getMatchingWords('??????'); // must return ['banana', 'papaya', 'cherry']
補(bǔ)充說(shuō)明:
(1)單詞和模式都是小寫
(2)返回單詞的順序無(wú)關(guān)緊要
上面這道題目是典型的 正則表達(dá)式應(yīng)用題磕蛇,考察的知識(shí)點(diǎn)是2個(gè):
(1)使用 RegExp 對(duì)象 動(dòng)態(tài)創(chuàng)建正則表達(dá)式
(2)使用 /./
匹配一個(gè)任意字符
因此不難有如下解決方案(ps:這個(gè)是我的解決方案景描,雖然解法比較low,但是邏輯應(yīng)該還算清晰秀撇,容易理解)
// 字典構(gòu)造器
function Dictionary(words) {
this.words = words;
}
// 原型里拓展解法
Dictionary.prototype.getMatchingWords = function(pattern) {
let res = []
const reg = new RegExp("^" + pattern.replace(/\?/g, '.') + "$") // 創(chuàng)建正則表達(dá)式
for (let x of this.words) {
if (reg.test(x)) res.push(x)
}
return res
}
如果你有更好的解法超棺,歡迎評(píng)論留言哈 _
正則表達(dá)式模式
一個(gè)正則表達(dá)式模式是由簡(jiǎn)單的字符所構(gòu)成的,比如 /abc/
呵燕;或者是簡(jiǎn)單和特殊字符的組合棠绘,比如 /ab*c/
或 /Chapter (\d+)\.\d*/
簡(jiǎn)單模式
簡(jiǎn)單模式是由想要匹配的具體字符組成,且嚴(yán)格匹配字符順序再扭。比如氧苍,/abc/
這個(gè)模式就能且僅能匹配 "abc" 字符按照順序同時(shí)出現(xiàn)的情況,而 "bac" 或 "cab" 等就無(wú)法匹配泛范。
特殊字符
當(dāng)需要匹配一個(gè)不確定的字符串時(shí)让虐,比如尋找一個(gè)或多個(gè) "b",或者尋找空格罢荡,可以在模式中使用特殊字符赡突。特殊字符還包括如下:
- 斷言:表示一個(gè)匹配在某些條件下發(fā)生。斷言包括先行斷言区赵、后行斷言和條件表達(dá)式
- 字符類:區(qū)分不同類型的字符惭缰,例如區(qū)分字母和數(shù)字
- 組和范圍:表示表達(dá)式字符的分組和范圍
- 量詞:表示匹配的字符或條件表達(dá)式的數(shù)量
- Unicode屬性轉(zhuǎn)義:基于 Unicode字符屬性區(qū)分字符,例如大寫和小寫字母笼才、數(shù)字符合和標(biāo)點(diǎn)
Escaping
當(dāng)需要使用任何特殊字符的字面值(例如从媚,搜索字符 *
),你必須通過(guò)在它前面放一個(gè)反斜杠來(lái)轉(zhuǎn)義它患整。 例如拜效,要搜索'a'后跟*
后跟'b'喷众,你應(yīng)該使用 /a\*b/
- 反斜杠“轉(zhuǎn)義”字符 *
,使其成為文字而非特殊符號(hào)紧憾。將用戶輸入轉(zhuǎn)義為正則表達(dá)式中的一個(gè)字面字符串到千,可以通過(guò)簡(jiǎn)單的替換來(lái)實(shí)現(xiàn):
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); //$&表示整個(gè)被匹配的字符串
}
使用正則表達(dá)式
前面講到,正則表達(dá)式可以被用于 RegExp 的 exec
和 test
方法以及 String 的 match
赴穗、replace
憔四、search
和 split
方法。這些方法在 JavaScript 手冊(cè) 中有詳細(xì)的解釋般眉,下面只簡(jiǎn)單羅列下各自功能了赵,不做展開:
-
exec
:在字符串中執(zhí)行查找匹配的RegExp
方法,它返回一個(gè)數(shù)組(未匹配到則返回null
) -
test
:在字符串中測(cè)試是否匹配的RegExp
方法甸赃,它返回true
或false
-
match
:在字符串中執(zhí)行查找匹配的String
方法柿汛,它返回一個(gè)數(shù)組,在未匹配到時(shí)會(huì)返回null
-
matchAll
:在字符串中執(zhí)行查找所有匹配的String
方法埠对,它返回一個(gè)迭代器(iterator
) -
search
:在字符串中測(cè)試匹配的String
方法络断,它返回匹配到的位置索引,或者在失敗時(shí)返回 -1 -
replace
:在字符串中執(zhí)行查找匹配的String
方法项玛,并且使用替換字符串替換掉匹配到的子字符串 -
split
:使用正則表達(dá)式或者一個(gè)固定字符串分隔一個(gè)字符串的String
方法貌笨,并將分隔后的子字符串存儲(chǔ)到數(shù)組中
一個(gè)簡(jiǎn)單的快速記憶方法:
(1)想要知道在一個(gè)字符串中的一個(gè)匹配是否被找到,使用 test
或 search
方法
(2)想得到更多的信息(但是比較慢)則可以使用 exec
或 match
方法
舉個(gè)栗子襟沮,使用exec方法在一個(gè)字符串中查找一個(gè)匹配:
const myRe = /d(b+)d/g;
const myArray = myRe.exec("cdbbdbsbz");
如果不需要訪問正則表達(dá)式的屬性锥惋,這個(gè)腳本通過(guò)另一個(gè)方法來(lái)創(chuàng)建myArray:
const myArray = /d(b+)d/g.exec("cdbbdbsbz");
// 和 "cdbbdbsbz".match(/d(b+)d/g); 相似。
// 但是 "cdbbdbsbz".match(/d(b+)d/g) 輸出數(shù)組 [ "dbbd" ]开伏,
// 而 /d(b+)d/g.exec('cdbbdbsbz') 輸出數(shù)組 [ "dbbd", "bb", index: 1, input: "cdbbdbsbz" ].
如果想通過(guò)一個(gè)字符串構(gòu)建正則表達(dá)式膀跌,那么這個(gè)腳本還有另一種方法:
const myRe = new RegExp("d(b+)d", "g");
const myArray = myRe.exec("cdbbdbsbz");
使用括號(hào)的子字符串匹配
一個(gè)正則表達(dá)式模式使用括號(hào),將導(dǎo)致相應(yīng)的子匹配被記住硅则。例如淹父,/a(b)c /
可以匹配字符串“abc”株婴,并且記得“b”怎虫。回調(diào)這些括號(hào)中匹配的子串困介,使用數(shù)組元素[1],……[n]大审。
使用括號(hào)匹配的子字符串的數(shù)量是無(wú)限的。返回的數(shù)組中保存所有被發(fā)現(xiàn)的子匹配座哩。下面的例子說(shuō)明了如何使用括號(hào)的子字符串匹配徒扶。
下面的腳本使用 replace()
方法來(lái)轉(zhuǎn)換字符串中的單詞。在匹配到的替換文本中根穷,腳本使用替代的$1
, $2
表示第一個(gè)和第二個(gè)括號(hào)的子字符串匹配:
const re = /(\w+)\s(\w+)/;
const str = "John Smith";
const newstr = str.replace(re, "$2, $1");
console.log(newstr); // 輸出 "Smith, John"
通過(guò)標(biāo)志進(jìn)行高級(jí)搜索
正則表達(dá)式有六個(gè)可選參數(shù) (flags) 允許全局和不分大小寫搜索等姜骡。這些參數(shù)既可以單獨(dú)使用也能以任意順序一起使用, 并且被包含在正則表達(dá)式實(shí)例中:
-
g
:全局搜索 -
i
:不區(qū)分大小寫搜索 -
m
: 多行搜索 -
s
:允許.
匹配換行符 -
u
:使用Unicode碼的模式進(jìn)行匹配 -
y
:執(zhí)行“粘性(sticky)”搜索, 匹配從目標(biāo)字符串的當(dāng)前位置開始
例如导坟,re = /\w+\s/g
將創(chuàng)建一個(gè)查找一個(gè)或多個(gè)字符后有一個(gè)空格的正則表達(dá)式,或者組合起來(lái)像此要求的字符串:
const re = /\w+\s/g;
const str = "fee fi fo fum";
const myArray = str.match(re);
console.log(myArray);
// ["fee ", "fi ", "fo "]
使用 .exec()
方法時(shí)圈澈,與 g
標(biāo)志關(guān)聯(lián)的行為是不同的惫周。 (“class”和“argument”的作用相反:在.match()
的情況下,字符串類(或數(shù)據(jù)類型)擁有該方法康栈,而正則表達(dá)式只是一個(gè)參數(shù)递递,而在.exec()
的情況下,它是擁有該方法的正則表達(dá)式啥么,其中字符串是參數(shù)登舞。對(duì)比str.match(re)
與re.exec(str)
), g
標(biāo)志與.exec()
方法一起使用獲得迭代進(jìn)展:
const xArray; while(xArray = re.exec(str)) console.log(xArray);
// produces:
// ["fee ", index: 0, input: "fee fi fo fum"]
// ["fi ", index: 4, input: "fee fi fo fum"]
// ["fo ", index: 7, input: "fee fi fo fum"]
除此之外,m
標(biāo)志用于指定多行輸入字符串應(yīng)該被視為多個(gè)行悬荣。如果使用m
標(biāo)志菠秒,^
和$
匹配的開始或結(jié)束輸入字符串中的每一行,而不是整個(gè)字符串的開始或結(jié)束隅熙。
@參考:正則表達(dá)式
本文由博客一文多發(fā)平臺(tái) OpenWrite 發(fā)布稽煤!