摘要:簡述正則表達(dá)式是處理字符串的利器,并提高工作效率,一個(gè)好的正則能夠幫我們省去幾十甚至上百行代碼。
簡述
正則表達(dá)式是處理字符串的利器,并提高工作效率,一個(gè)好的正則能夠幫我們省去幾十甚至上百行代碼。在工作中,也許你會見到在代碼中出現(xiàn)很多正則處理字符串,也可能見到代碼中毫無正則,原因在于會正則的人往往處理字符串首先想到用正則去處理,不會的那必然用很多API處理。并且在面試的時(shí)候很多同學(xué)往往掛在正則這里,所以對于前端正則是一個(gè)必備技能。這篇文章不光能教會你如何使用它,還能讓你懂得其中的原理,在以后使用和面試中將做到毫無懼怕。一.基礎(chǔ)
要想玩轉(zhuǎn)正則首先要明白三大元素:修飾符 元字符 量詞1.修飾符
例:var reg = /^d$/g 這是一個(gè)簡單點(diǎn)正則,下面我們來對三大元素一探究竟
g - global 全局匹配(只要有匹配成功的結(jié)果一直匹配直到?jīng)]有為止)
i - ignoreCase 忽略大小寫
m - multiline 多行匹配
2.元字符元字符其中分為特殊元字符和普通元字符
普通元字符就是列入數(shù)組,字母等元素
常用特殊元字符如下:
轉(zhuǎn)義字符(把一個(gè)普通字符轉(zhuǎn)變?yōu)橛刑厥庖饬x的字符,或者把一個(gè)有意義的字符轉(zhuǎn)變?yōu)槠胀ㄗ址?/p>
. 除了n(換行符)以外的任意字符
d 匹配一個(gè)0~9之間的數(shù)字
D 匹配一個(gè)非0~9之間的數(shù)字(大寫與小寫字母組合正好是相反含義)??
w 匹配一個(gè)0~9或字母或_之間的一個(gè)字符
s 匹配一個(gè)任意空白字符
匹配一個(gè)邊界符
x|y 匹配x或者y中的一個(gè)
[a-z] 匹配a-z中的任意一個(gè)字符
[^a-z] 匹配非a-z中的任意一個(gè)字符
[xyz] 匹配x或y或z中的一個(gè)字符
[^xyz] 和上方相反
() 整的小分組,匹配一個(gè)小分組(可以理解為大正則中的一個(gè)小正則)
^ 以某一個(gè)元字符開始
$ 以某一個(gè)元字符結(jié)束
?: 只匹配不捕獲
?= 正向肯定預(yù)查
?! 正向否定預(yù)查
3.量詞量詞主要的作用是用來描述元字符出現(xiàn)的次數(shù) 如下:
+ 讓前面的元字符出現(xiàn)一到多次
? 出現(xiàn)零到一次
* 出現(xiàn)零到多次
{n} 出現(xiàn)n次
{n,} 出現(xiàn)n到多次
{n,m} 出現(xiàn)n到m次
看到這里大家一定有些暈,這些稀奇古怪的符號,到底如何運(yùn)用,下面將帶大家去運(yùn)用這些字符,在運(yùn)用之前同學(xué)們要做到牢記 牢記 牢記這些字符,想要玩轉(zhuǎn)正則必須要的就是牢記他們,當(dāng)你牢記這些字符的同時(shí)說明你已經(jīng)入門了。二.元字符
1.開始元字符 ^
匹配啟示位置的元字符,例:var reg = /^2/; 表示開頭必須是2,如果開始元字符放在[]里面
例:[^]表示非中括號種情況 相反含義
2.結(jié)束元字符 $
匹配結(jié)束位置的元字符,例: var reg = /2$/; 表示結(jié)尾必須是2,如果是var reg = /^2$/; 表示只能為2,因?yàn)?只代表一個(gè)元字符。
3.轉(zhuǎn)義字符
將特殊元字符轉(zhuǎn)換為普通字符,例:var reg = /^2.3$/ 正常理解為匹配啟示為2 結(jié)束為3中間是.的正則,但是在這里面.屬于特殊元字符,意義是除了 (換行符)以外的任意字符,所以不論是2.3/2+3/2s.3等等,只要是不· 都匹配成功,所以為了這種需求就用到了轉(zhuǎn)義字符 如下: var reg = /^2.3$/ 將特殊元字符.轉(zhuǎn)義為真正的.元素,再次匹配只有2.3才能匹配成功 如下思考:
var reg1 = /^d$/ var reg2 = /^d$/ var reg3 = /^d$/ var reg4 = /^d$/
首先reg1 表示0-9之間的數(shù)字 所以0-9都能匹配成功
reg2出現(xiàn)兩個(gè) 不論是0-9 d d都匹配失敗,只有d才匹配成功,原因在于第一個(gè)轉(zhuǎn)義字符把第二個(gè)轉(zhuǎn)義為普通,此時(shí)第一個(gè)也表示普通字符,所以只有匹配到d才生效
reg3出現(xiàn)三個(gè),此時(shí)大家一定會認(rèn)為d才是正確答案,非也,此時(shí)的正確答案是[0-9]意思是和0-9中任意一個(gè)數(shù)字,原因在于第一個(gè)將第二個(gè)轉(zhuǎn)義,所以變?yōu)?b> d分為了兩部分,為普通字符,而d表示一個(gè)0~9之間的數(shù)字,所以正確答案是[0-9]
reg4出現(xiàn)四個(gè) 很多同學(xué)會認(rèn)為正確答案一定是[0-9], 很可惜,正確的是d,原因是當(dāng)?shù)谝粋€(gè)把第二個(gè)轉(zhuǎn)義為普通字符時(shí),第三個(gè)又把第四個(gè)轉(zhuǎn)義為普通字符,所以最后匹配為d
看到這里相信有一部分小伙伴已經(jīng)暈了,雖然在工作我們不會玩這種操作,但是要深刻理解轉(zhuǎn)義字符,在正則中如果你直接寫 var reg = /^$/會報(bào)錯(cuò),因?yàn)檎齽t中不能多帶帶一個(gè)出現(xiàn),因?yàn)樗且粋€(gè)特殊元字符,需要寫至少兩個(gè), 例如: var reg = /^$/ 正確的匹配結(jié)果為"",所以牢記兩個(gè)代表真正的,這里搞明白的同學(xué),相信轉(zhuǎn)義字符已經(jīng)完全掌握。
4.或者元字符 x|y
這個(gè)元字符很好理解就是匹配x或者匹配y,沒有什么難度,舉個(gè)小例子:
var reg = /2|3/ // 匹配數(shù)字為2或者為3
5.小分組 ()
在上面同學(xué)們會發(fā)現(xiàn)用了()這樣的元字符,他主要的特點(diǎn)就是將括號內(nèi)的正則規(guī)則看成一個(gè)整體,相當(dāng)于一個(gè)小的獨(dú)立的正則,主要處理如下例子中的問題
var reg = /^18|19$/ // 這個(gè)例子很多同學(xué)能夠了解是18或者19開頭 但是結(jié)尾呢?真的只匹配19么? 其實(shí)并不是 // 正確的匹配除了18 19 還有181和189 這時(shí)候小分組就起到了作用如下 var reg = /^(18|19)$/ // 這里將18或19用()包裹起來,起到小分組的作用 // 這樣這個(gè)正則只匹配18開頭結(jié)尾或者19而不是181和189
6.分組引用
分組引用的概念就是可以引用大正則中指定的小正則規(guī)則,例如:
var reg = /^([a-z])([a-z])2([a-z])$/ // 符合的字符串:book week http ...?
具體上面的例子理解為2代表著第二個(gè)小正則規(guī)則的完全引用,就是和第二個(gè)小正則([a-z])一樣,可以減少正則的復(fù)雜度和處理多次重復(fù)規(guī)則
7.匹配字符 []
[xyz]、[^xyz]、[a-z]、[^a-z]下面舉個(gè)小例子,便于同學(xué)們理解
var reg = /^[a-zA_Z0-9_]$/ // 這個(gè)正則和等價(jià)于w 就是匹配一個(gè)0~9或字母或_之間的一個(gè)字符 // 而正則[xyz]中的xyz分別代表a-z、A_Z、0-9,xyz只是一個(gè)代表標(biāo)識,可以有xyzhw各種組合 // 就像這個(gè)例子中有下劃線_一樣四個(gè)的匹配 // 有一個(gè)重點(diǎn)補(bǔ)充,在[]中的特殊元字符一般都代表本身含義,如下 var reg = /^[.?+&]$/ // 代表著匹配. .? ?+ ...等等
8.邊界符
匹配一個(gè)單詞邊界,也就是指單詞和空格間的位置(邊界主要是單詞的左右兩邊) 例如:
var reg = /er/ // 可以匹配never中的er,但是不能匹配verb中的er var reg = /w+/g // 能匹配字母數(shù)字和下劃線與單詞邊界 "my blog is www.ngaiwe.com" // 能匹配 "my"、"blog"、"is"、"www"、"ngaiwe"、"com"
9.只匹配不捕獲 ?:
下面舉一個(gè)例子,但是涉及到捕獲內(nèi)容,如果同學(xué)們不太明白,可以先跳過此處,看完下面捕獲,再返回來看
var reg = /^(d{6})(d{4})(d{2})(d{2})d{2}(d)(d|X)$/g var str = "110105199001220613" console.log(reg.exec(str)) // 打印結(jié)果為 "110105199001220613", "110105", "1990", "01", "22", "1", "3" var reg = /^(d{6})(?:d{4})(d{2})(d{2})d{2}(d)(d|X)$/g // 打印結(jié)果為 "110105199001220613", "110105", "01", "22", "1", "3" // 會將第二個(gè)小分組只匹配,不捕獲
10.正向肯定預(yù)查 ?=
這個(gè)概念比較難理解,用于就是為了匹配一個(gè)元素后面是的元素是否符合相應(yīng)規(guī)則,但是并不消耗這個(gè)規(guī)則,例子1:
var reg = /windows(?=95|98|NT|2000)/ var str1 = "windows2000" var str2 = "windowsxp" console.log(reg.test(str1)) console.log(reg.test(str2)) // str1 為true str2 為false console.log(reg.exec(str1)) console.log(reg.exec(str2)) // 能捕獲到str1 并且捕獲結(jié)果時(shí)windows 并沒有將2000也同時(shí)捕獲 // 說明正向預(yù)查只負(fù)責(zé)匹配相應(yīng)規(guī)則
例子2:
var reg1 = /win(?=d)dows/ var reg2 = /win(d)dows/ var str = "windows" console.log(reg1.test(str)) console.log(reg2.test(str)) // reg1 返回true reg2返回 false // 原因是正向預(yù)查只負(fù)責(zé)匹配,不消耗字符,也就是并不會匹配為里面規(guī)則的字符 // reg1 相當(dāng)于匹配windows并且符合win后面第一個(gè)出現(xiàn)的是d // reg2 相當(dāng)于匹配winddows
11.正想否定預(yù)查 ?!
和正向肯定預(yù)查相反,匹配不符合規(guī)則的正則三.正則的兩種創(chuàng)建方式
正則的創(chuàng)建方式分為兩種,一種是字面量創(chuàng)建,另一種是構(gòu)造函數(shù)創(chuàng)建
1.字面量創(chuàng)建
var reg = /d+/img
2.構(gòu)造函數(shù)創(chuàng)建
var reg = new RegExp("d+", "img") 第一個(gè)參數(shù)是元字符并且d這種特殊字符在這里面是普通字符,所以需要用轉(zhuǎn)義為特殊字符,第二個(gè)參數(shù)是修飾符這兩種的用途有區(qū)別,一般需要?jiǎng)討B(tài)創(chuàng)建正則元字符采用構(gòu)造函數(shù)創(chuàng)建,因?yàn)槔锩嬖址亲址唇樱R?guī)固定寫死正則采用字面量創(chuàng)建,例子如下:
var stringMode = "string" var reg = new RegExp(`^[object ${stringMode}]$`) console.log(reg.toString())四.正則原型方法
首相上一張圖讓同學(xué)們看一下正則一共有哪些方法,如下:
可以看到正則原型對象上一共就三個(gè)方法,exec test和toString
1.exec該方法主要應(yīng)用于捕獲組而設(shè)計(jì),實(shí)參是要匹配的字符串。如圖所示:
#### 捕獲原理 - 1.在捕獲的時(shí)候先驗(yàn)證當(dāng)前字符串和正則是否匹配,不匹配返回null(沒有捕獲到任何內(nèi)容) - 2.如果匹配從字符串最左邊開始,向右查找到匹配內(nèi)容,并把匹配的內(nèi)容返回 #### 捕獲結(jié)果 - 1.結(jié)果是一個(gè)數(shù)組 - 2.第一項(xiàng)0 是當(dāng)前本次大正則中匹配的結(jié)果 - 3.`index `是匹配到的結(jié)果在字符串中的索引位置 - 4.`input `當(dāng)前正則操作的原始字符串 - 5.如果大正則中有分組`()`,獲取的數(shù)組中從第二項(xiàng)開始都是每個(gè)小分組的捕獲結(jié)果 - 下面舉一個(gè)身份證正則的例子 便于參考,具體里面匹配規(guī)則下面會多帶帶介紹,這里只學(xué)習(xí)字段意義 ![正則exec方法](https://user-gold-cdn.xitu.io/2018/8/2/164f88db52e630a1?w=973&h=307&f=png&s=51301)
2.懶惰性
正則捕獲存在懶惰性,在上面exec中,執(zhí)行一次exec只捕獲到第一個(gè)符合規(guī)則的內(nèi)容,第二次執(zhí)行exec也是捕獲到第一個(gè)內(nèi)容,后面的內(nèi)容不論執(zhí)行多少次都無法捕獲到解決方法
在正則的末尾加修飾符g(全局匹配)原理
如圖所示,正則本身有一個(gè)屬性 lastIndex 下一次正則在字符串中匹配查找的開始索引
默認(rèn)值是0,從字符串第一個(gè)位置開始查找,由此可見,當(dāng)執(zhí)行完exec后lastIndex并沒有變,并且就算手動(dòng)修改lastIndex也不會起作用,瀏覽器不識別
加上了修飾符g就解決了這個(gè)問題,因?yàn)槊恳淮蝒xec之后,瀏覽器默認(rèn)會修改lastIndex,下一次從上一次結(jié)束的位置開始查找,所以可以得到后面內(nèi)容
我們來手動(dòng)創(chuàng)建一個(gè)函數(shù)來實(shí)現(xiàn)匹配到全部內(nèi)容并且都捕獲到,如下:
var reg = /^(d{6})(d{4})(d{2})(d{2})d{2}(d)(d|X)$/g var str = "110105199001220613" RegExp.prototype.myExec = function myExec() { var str = arguments[0] || "" var result = [] // 首先this指向的是RegExp,所以判斷this是否加了全局修飾符g // 如果沒有,防止執(zhí)行死循環(huán),我們只執(zhí)行一次exec并將其返回即可 if(!this.global) { return this.exec(str) } var arrs = this.exec(str) while(arrs) { result.push(arrs[0]) // 此時(shí)lastIndex的值已經(jīng)變?yōu)樯弦淮蔚慕Y(jié)尾 arrs = this.exec(str) } return result }
這個(gè)方法當(dāng)正則reg加了修飾符g 則返回大正則匹配到結(jié)果,如果沒加g則返回exec捕獲結(jié)果
3.test 該方法主要應(yīng)用于正則匹配,當(dāng)然也可以用在捕獲上面
從字符串左側(cè)開始匹配,匹配到符合正則規(guī)則的字符,返回true,否則返回false,同樣的test在修飾符g下也會修改lastIndex的值運(yùn)用test實(shí)現(xiàn)捕獲
var reg = /{([a-z]+)}/g var str = "my name is {weiran}. I am from {china}" var result = [] while (reg.test(str)) { result.push(RegExp.$1) } console.log(result) // ["weiran", "china"]
當(dāng)test匹配到結(jié)尾或者匹配不到時(shí),返回false,成功則向數(shù)組添加當(dāng)前小分組匹配第一個(gè)元素內(nèi)容
在RegExp的constructor中存在$1-$9,他們的具體指的是當(dāng)前本次匹配小分組第一到第九捕獲的內(nèi)容
4.toString
就是將正則表達(dá)式轉(zhuǎn)化為字符串五.字符串正則方法
1.match
同樣是捕獲的方法,如圖所示:
當(dāng)加了修飾符g,返回的是大正則匹配結(jié)果組成的數(shù)組,不加修飾符g則返回大正則和每個(gè)小分組返回結(jié)果組成的數(shù)組,跟上面我們手寫的myExec一樣,其實(shí)原理就是我們上面寫的方法,如果想在加了修飾符g的時(shí)候返回結(jié)果和沒加一樣,所以在直接用match方法就能將匹配內(nèi)容全部捕獲到。
但是他也有局限性,就想上面說的在加了修飾符g的時(shí)候,會忽略小分組捕獲內(nèi)容,只捕獲大正則捕獲內(nèi)容,解決辦法就向上面myExec一樣,將arrs[0]改為arrs,在每次匹配到結(jié)果時(shí),將每個(gè)小分組也保存下來。
2.replace
主要運(yùn)用在替換,其中兩個(gè)參數(shù),第一個(gè)為要替換的字符串或者正則,第二個(gè)是替換內(nèi)容或一個(gè)返回函數(shù),具體操作如下:
var str = "my name is {weiran}, my blog is {ngaiwe}" var reg = /{([a-z]+)}/ str = str.replace(reg, "123") console.log(str) // 打印出 my name is 123, my blog is {ngaiwe} // 同學(xué)們會發(fā)現(xiàn)和exec的懶惰性很相似,不加修飾符g 只匹配第一個(gè)lastIndex沒有改變 var reg = /{([a-z]+)}/g // 打印出 my name is 123, my blog is 123
并且replace不會修改原始字符串
var str = "my name is {weiran}, my blog is {ngaiwe}" var reg = /{([a-z]+)}/g str = str.replace(reg, function () { console.log(arguments) }) // 打印出當(dāng)前匹配的小分組,如果函數(shù)中沒有return出替換值,則返回undefined
3.split
按照正則方式可以拆分成數(shù)組,具體例子如下:
var str = "weiRanNgaiWe" var reg = /[A-Z]/ console.log(str.split(reg)) // ["wei", "an", "gai", "e"]按照大寫拆分成數(shù)組
4.search
類似于indexOf,返回匹配元素的起始位置,如果沒有返回-1,不支持修飾符g
var str = "ngaiwe@126.com" var reg = /d+/ console.log(str.search(reg)) // 返回 7六.實(shí)戰(zhàn)案例剖析
1.身份證號碼
舉個(gè)身份證的例子: 110105199109214237
由此分析前6位是數(shù)字地區(qū)區(qū)號組成,然后四位是年,兩位月,兩位日和四位隨機(jī),倒數(shù)第二位單數(shù)男性,雙數(shù)女性,最后一位可能是大寫X,所以根據(jù)這個(gè)規(guī)則的正則是
var str = "110105199109214237" var reg = /^(d{6})(d{4})(d{2})(d{2})d{2}(d)(d|X)$/ console.log(reg.exec(str)) // ["110105199109214237", "110105", "1991", "09", "21", "3", "7", index: 0, input: "110105199109214237", groups: undefined]
2.郵箱
舉個(gè)郵箱的例子:weiran@vipkid.com.cn
由此分析:
1.@前面可能是數(shù)字、字母、下劃線、-、.
2.-和.不能相連在一起
/^w+((-|w+)|(.w+))*/ 開頭一定是數(shù)字,字母或下劃線組成,后面的內(nèi)容可能是-與數(shù)字字母下劃線 或者.和數(shù)字字母下劃線組成的0到多個(gè)字符
3.@后面部分
首先一定是數(shù)字字母組成的多位字符
然后可能存在是.組成的郵箱后綴或者鏈接前方字符的.和-
最后肯定是.組成的郵箱后綴
var reg = /^w+((-|w+)|(.w+))*@[a-zA-Z0-9]+((.|-)[a-zA-Z0-9]+)*.[a-zA-Z0-9]+$/ var str = "weiran@vipkid.com.cn" console.log(reg.test(str)) // true
3.URL截取
舉個(gè)截取url參數(shù)的例子:
http://www.ngaiwe.com/page/in...
我們想要的是參數(shù)轉(zhuǎn)化鍵值對和哈希值{name: "weiran",age: 27, sex: 0, HASH: "develpoment"}
由此分析:
需要分為兩部分捕獲,首先第一次捕獲?后面的參數(shù),第二次捕獲#后面的hash值
首先匹配第一個(gè),他的規(guī)則是匹配等號兩邊所以是/()=()/,并且匹配的是非?&=#的特殊字符,將他們保存在obj對象中
其次匹配hash,方法和第一個(gè)類似只是匹配#后面的部分
String.prototype.myQueryURLParameter = function myQueryURLParameter () { var obj = {} this.replace(/([^?&=#]+)=([^?&=#]+)/g, function () { obj[arguments[1]] = arguments[2] }) this.replace(/#([^?&=#]+)/g, function () { obj["HASH"] = arguments[1] }) return obj }七.總結(jié)
具體案例就就少到這里,網(wǎng)上有各種正則的案例,同學(xué)們以后看到案例具體分析他們是如何寫的,不要一味地使用,這樣才能在工作中不斷地思考,學(xué)習(xí)。八.博客
魏燃技術(shù)博客
有任何問題可留言或者發(fā)送本人郵箱ngaiwe@126.com
九.分享正則元字符表
正則在線測試工具
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/96569.html
摘要:面試官要不你來手寫下單例模式唄候選者單例模式一般會有好幾種寫法候選者餓漢式簡單懶漢式在方法聲明時(shí)加鎖雙重檢驗(yàn)加鎖進(jìn)階懶漢式靜態(tài)內(nèi)部類優(yōu)雅懶漢式枚舉候選者所謂餓漢式指的就是還沒被用到,就直接初始化了對象。面試官:我看你的簡歷寫著熟悉常見的設(shè)計(jì)模式,要不你來簡單聊聊你熟悉哪幾個(gè)吧?候選者:常見的工廠模式、代理模式、模板方法模式、責(zé)任鏈模式、單例模式、包裝設(shè)計(jì)模式、策略模式等都是有所了解的候選者:...
摘要:一般來說,阿里的面試會有兩輪的技術(shù)電面,分別交叉檢驗(yàn)?zāi)愕募夹g(shù)基礎(chǔ)。但從知識體系的角度來看,阿里面試對于知識的考核可以分為三個(gè)層次對于基礎(chǔ)知識的考核對于項(xiàng)目經(jīng)驗(yàn)的考核對于項(xiàng)目深度的考核。 最近去阿里的菜鳥國際做了一次面試交流,發(fā)現(xiàn)大公司對于面試者的知識結(jié)構(gòu)考核非常嚴(yán)謹(jǐn),可以作為我們?nèi)粘9ぷ鲗W(xué)習(xí)的指導(dǎo)。雖然很多人說面試問到的東西在實(shí)際工作中很少用到,甚至有「面試造火箭,工作擰螺絲」的說法。...
摘要:關(guān)鍵字驅(qū)動(dòng)的自動(dòng)化測試框架建立在數(shù)據(jù)驅(qū)動(dòng)手段之上,表中包含指令關(guān)鍵詞,而不只是數(shù)據(jù)。關(guān)鍵字驅(qū)動(dòng)的自動(dòng)化測試是對數(shù)據(jù)驅(qū)動(dòng)的自動(dòng)化測試的有效改進(jìn)和補(bǔ)充。 今天,我們來...
摘要:大多數(shù)待遇豐厚的開發(fā)職位都要求開發(fā)者精通多線程技術(shù)并且有豐富的程序開發(fā)調(diào)試優(yōu)化經(jīng)驗(yàn),所以線程相關(guān)的問題在面試中經(jīng)常會被提到。將對象編碼為字節(jié)流稱之為序列化,反之將字節(jié)流重建成對象稱之為反序列化。 JVM 內(nèi)存溢出實(shí)例 - 實(shí)戰(zhàn) JVM(二) 介紹 JVM 內(nèi)存溢出產(chǎn)生情況分析 Java - 注解詳解 詳細(xì)介紹 Java 注解的使用,有利于學(xué)習(xí)編譯時(shí)注解 Java 程序員快速上手 Kot...
閱讀 1208·2021-11-22 12:05
閱讀 1335·2021-09-29 09:35
閱讀 629·2019-08-30 15:55
閱讀 3121·2019-08-30 14:12
閱讀 954·2019-08-30 14:11
閱讀 2874·2019-08-30 13:10
閱讀 2400·2019-08-29 16:33
閱讀 3326·2019-08-29 11:02