正則表達式是處理字符串的利器,並提升工做效率,一個好的正則可以幫咱們省去幾十甚至上百行代碼。在工做中,也許你會見到在代碼中出現不少正則處理字符串,也可能見到代碼中毫無正則,緣由在於會正則的人每每處理字符串首先想到用正則去處理,不會的那必然用不少API處理。而且在面試的時候不少同窗每每掛在正則這裏,因此對於前端正則是一個必備技能。這篇文章不光能教會你如何使用它,還能讓你懂得其中的原理,在之後使用和麪試中將作到毫無害怕。javascript
要想玩轉正則首先要明白三大元素:
修飾符
元字符
量詞
例:var reg = /^\d$/g 這是一個簡單點正則,下面咱們來對三大元素一探究竟html
g
- global 全局匹配(只要有匹配成功的結果一直匹配直到沒有爲止)i
- ignoreCase 忽略大小寫m
- multiline 多行匹配元字符其中分爲特殊元字符和普通元字符
普通元字符就是列入數組,字母等元素
經常使用特殊元字符以下:前端
\
轉義字符(把一個普通字符轉變爲有特殊意義的字符,或者把一個有意義的字符轉變爲普通字符).
除了\n(換行符)之外的任意字符\d
匹配一個0~9之間的數字\D
匹配一個非0~9之間的數字(大寫與小寫字母組合正好是相反含義\w
匹配一個0~9或字母或_之間的一個字符\s
匹配一個任意空白字符\b
匹配一個邊界符x|y
匹配x或者y中的一個[a-z]
匹配a-z中的任意一個字符[^a-z]
匹配非a-z中的任意一個字符[xyz]
匹配x或y或z中的一個字符[^xyz]
和上方相反()
整的小分組,匹配一個小分組(能夠理解爲大正則中的一個小正則)^
以某一個元字符開始$
以某一個元字符結束?:
只匹配不捕獲?=
正向確定預查?!
正向否認預查量詞主要的做用是用來描述元字符出現的次數 以下:java
+
讓前面的元字符出現一到屢次?
出現零到一次*
出現零到屢次{n}
出現n次{n,}
出現n到屢次{n,m}
出現n到m次看到這裏你們必定有些暈,這些稀奇古怪的符號,到底如何運用,下面將帶你們去運用這些字符,在運用以前同窗們要作到牢記 牢記 牢記這些字符,想要玩轉正則必需要的就是牢記他們,當你牢記這些字符的同時說明你已經入門了。面試
1.開始元字符 ^
正則表達式
匹配啓示位置的元字符,例:
var reg = /^2/;
表示開頭必須是2,若是開始元字符放在[]裏面 例:[^]表示非中括號種狀況 相反含義windows
2.結束元字符 $
數組
匹配結束位置的元字符,例:
var reg = /2$/;
表示結尾必須是2,若是是var reg = /^2$/;
表示只能爲2,由於2只表明一個元字符。瀏覽器
3.轉義字符 \
函數
將特殊元字符轉換爲普通字符,例:
var reg = /^2.3$/
正常理解爲匹配啓示爲2 結束爲3中間是.
的正則,可是在這裏面.
屬於特殊元字符,意義是除了\n
(換行符)之外的任意字符,因此不管是2.3/2+3/2s.3等等,只要是不·\n
都匹配成功,因此爲了這種需求就用到了轉義字符\
以下: var reg = /^2\.3$/ 將特殊元字符.
轉義爲真正的.
元素,再次匹配只有2.3才能匹配成功 以下思考:
var reg1 = /^\d$/
var reg2 = /^\\d$/
var reg3 = /^\\\d$/
var reg4 = /^\\\\d$/
複製代碼
首先reg1 表示0-9之間的數字 因此0-9都能匹配成功
reg2出現兩個\
不管是0-9 d \d都匹配失敗,只有\\d
才匹配成功,緣由在於第一個轉義字符把第二個\
轉義爲普通\
,此時第一個\
也表示普通字符,因此只有匹配到\\d
才生效
reg3出現三個\
,此時你們必定會認爲\\\d
纔是正確答案,非也,此時的正確答案是\\[0-9]
意思是\和0-9中任意一個數字,緣由在於第一個\
將第二個轉義,因此變爲\\ \d
分爲了兩部分,\\
爲普通字符,而\d
表示一個0~9之間的數字,因此正確答案是\\[0-9]
reg4出現四個\
不少同窗會認爲正確答案必定是\\\[0-9]
, 很惋惜,正確的是\\\\d
,緣由是當第一個把第二個轉義爲普通字符時,第三個又把第四個轉義爲普通字符,因此最後匹配爲\\\\d
看到這裏相信有一部分小夥伴已經暈了,雖然在工做咱們不會玩這種操做,可是要深入理解轉義字符,在正則中若是你直接寫 var reg = /^$/會報錯,由於正則中不能單獨一個\
出現,由於他是一個特殊元字符,須要寫至少兩個\
, 例如:var reg = /^\\$/
正確的匹配結果爲'\\'
,因此牢記兩個\
表明真正的\
,這裏搞明白的同窗,相信轉義字符已經徹底掌握。
4.或者元字符 x|y
這個元字符很好理解就是匹配x或者匹配y,沒有什麼難度,舉個小例子:
var reg = /2|3/
// 匹配數字爲2或者爲3
複製代碼
5.小分組 ()
在上面同窗們會發現用了
()
這樣的元字符,他主要的特色就是將括號內的正則規則當作一個總體,至關於一個小的獨立的正則,主要處理以下例子中的問題
var reg = /^18|19$/
// 這個例子不少同窗可以瞭解是18或者19開頭 可是結尾呢?真的只匹配19麼? 其實並非
// 正確的匹配除了18 19 還有18一、18九、819 這時候小分組就起到了做用以下
var reg = /^(18|19)$/
// 這裏將18或19用()包裹起來,起到小分組的做用
// 這樣這個正則只匹配18開頭結尾或者19而不是181和189
複製代碼
6.分組引用 \n
分組引用的概念就是能夠引用大正則中指定的小正則規則,例如:
var reg = /^([a-z])([a-z])\2([a-z])$/
// 符合的字符串:book week http ...
複製代碼
具體上面的例子理解爲
\2
表明着第二個小正則規則的徹底引用,就是和第二個小正則([a-z])
同樣,能夠減小正則的複雜度和處理屢次重複規則
7.匹配字符 []
[xyz]
、[^xyz]
、[a-z]
、[^a-z]
下面舉個小例子,便於同窗們理解
var reg = /^[a-zA_Z0-9_]$/
// 這個正則和等價於\w 就是匹配一個0~9或字母或_之間的一個字符
// 而正則[xyz]中的xyz分別表明a-z、A_Z、0-9,xyz只是一個表明標識,能夠有xyzhw各類組合
// 就像這個例子中有下劃線_同樣四個的匹配
// 有一個重點補充,在[]中的特殊元字符通常都表明自己含義,以下
var reg = /^[.?+&]$/
// 表明着匹配. .? ?+ ...等等
複製代碼
8.邊界符 \b
匹配一個單詞邊界,也就是指單詞和空格間的位置(邊界主要是單詞的左右兩邊) 例如:
var reg = /er\b/
// 能夠匹配never中的er,可是不能匹配verb中的er
var reg = /\b\w+\b/g
// 能匹配字母數字和下劃線與單詞邊界 'my blog is www.ngaiwe.com'
// 能匹配 'my'、'blog'、'is'、'www'、'ngaiwe'、'com'
複製代碼
9.只匹配不捕獲 ?:
下面舉一個例子,可是涉及到捕獲內容,若是同窗們不太明白,能夠先跳過此處,看完下面捕獲,再返回來看
var reg = /^(\d{6})(\d{4})(\d{2})(\d{2})\d{2}(\d)(\d|X)$/g
var str = '110105199001220613'
console.log(reg.exec(str))
// 打印結果爲 "110105199001220613", "110105", "1990", "01", "22", "1", "3"
var reg = /^(\d{6})(?:\d{4})(\d{2})(\d{2})\d{2}(\d)(\d|X)$/g
// 打印結果爲 "110105199001220613", "110105", "01", "22", "1", "3"
// 會將第二個小分組只匹配,不捕獲
複製代碼
10.正向確定預查 ?=
這個概念比較難理解,用於就是爲了匹配一個元素後面是的元素是否符合相應規則,可是並不消耗這個規則,例子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 而且捕獲結果時windows 並無將2000也同時捕獲
// 說明正向預查只負責匹配相應規則
複製代碼
例子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
// 緣由是正向預查只負責匹配,不消耗字符,也就是並不會匹配爲裏面規則的字符
// reg1 至關於匹配windows而且符合win後面第一個出現的是d
// reg2 至關於匹配winddows
複製代碼
11.正想否認預查 ?!
和正向確定預查相反,匹配不符合規則的正則
正則的建立方式分爲兩種,一種是字面量建立,另外一種是構造函數建立
var reg = /\d+/img
var reg = new RegExp('\\d+', 'img')
第一個參數是元字符而且\d這種特殊字符在這裏面是普通字符,因此須要用\轉義爲特殊字符,第二個參數是修飾符
這兩種的用途有區別,通常須要動態建立正則元字符采用構造函數建立,由於裏面元字符是字符串拼接,常規固定寫死正則採用字面量建立,例子以下:
var stringMode = 'string'
var reg = new RegExp(`^\\[object ${stringMode}\\]$`)
console.log(reg.toString())
複製代碼
首相上一張圖讓同窗們看一下正則一共有哪些方法,以下:
能夠看到正則原型對象上一共就三個方法,
exec
test
和toString
1.exec
該方法主要應用於捕獲組而設計,實參是要匹配的字符串。如圖所示:
index
是匹配到的結果在字符串中的索引位置input
當前正則操做的原始字符串()
,獲取的數組中從第二項開始都是每一個小分組的捕獲結果2.懶惰性
正則捕獲存在懶惰性,在上面exec中,執行一次exec只捕獲到第一個符合規則的內容,第二次執行exec也是捕獲到第一個內容,後面的內容不論執行多少次都沒法捕獲到
在正則的末尾加修飾符g(全局匹配)
如圖所示,正則自己有一個屬性
lastIndex
下一次正則在字符串中匹配查找的開始索引
默認值是0,從字符串第一個位置開始查找,因而可知,當執行完exec後lastIndex
並無變,而且就算手動修改lastIndex
也不會起做用,瀏覽器不識別
加上了修飾符g就解決了這個問題,由於每一次exec以後,瀏覽器默認會修改
lastIndex
,下一次從上一次結束的位置開始查找,因此能夠獲得後面內容
咱們來手動建立一個函數來實現匹配到所有內容而且都捕獲到,以下:
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
// 若是沒有,防止執行死循環,咱們只執行一次exec並將其返回便可
if(!this.global) {
return this.exec(str)
}
var arrs = this.exec(str)
while(arrs) {
result.push(arrs[0])
// 此時lastIndex的值已經變爲上一次的結尾
arrs = this.exec(str)
}
return result
}
複製代碼
這個方法當正則reg加了修飾符g 則返回大正則匹配到結果,若是沒加g則返回exec捕獲結果
3.test
該方法主要應用於正則匹配,固然也能夠用在捕獲上面
從字符串左側開始匹配,匹配到符合正則規則的字符,返回true,不然返回false,一樣的
test
在修飾符g下也會修改lastIndex
的值
test
實現捕獲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']
複製代碼
當test匹配到結尾或者匹配不到時,返回false,成功則向數組添加當前小分組匹配第一個元素內容 在RegExp的constructor中存在
$1
-$9
,他們的具體指的是當前本次匹配小分組第一到第九捕獲的內容
4.toString
就是將正則表達式轉化爲字符串
1.match
一樣是捕獲的方法,如圖所示:
當加了修飾符g,返回的是大正則匹配結果組成的數組,不加修飾符g則返回大正則和每一個小分組返回結果組成的數組,跟上面咱們手寫的myExec同樣,其實原理就是咱們上面寫的方法,若是想在加了修飾符g的時候返回結果和沒加同樣,因此在直接用
match
方法就能將匹配內容所有捕獲到。 可是他也有侷限性,就想上面說的在加了修飾符g的時候,會忽略小分組捕獲內容,只捕獲大正則捕獲內容,解決辦法就向上面myExec同樣,將arrs[0]改成arrs,在每次匹配到結果時,將每一個小分組也保存下來。
2.replace
主要運用在替換,其中兩個參數,第一個爲要替換的字符串或者正則,第二個是替換內容或一個返回函數,具體操做以下:
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}
// 同窗們會發現和exec的懶惰性很類似,不加修飾符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)
})
// 打印出當前匹配的小分組,若是函數中沒有return出替換值,則返回undefined
複製代碼
3.split
按照正則方式能夠拆分紅數組,具體例子以下:
var str = 'weiRanNgaiWe'
var reg = /[A-Z]/
console.log(str.split(reg))
// ["wei", "an", "gai", "e"]按照大寫拆分紅數組
複製代碼
4.search
相似於
indexOf
,返回匹配元素的起始位置,若是沒有返回-1,不支持修飾符g
var str = 'ngaiwe@126.com'
var reg = /\d+/
console.log(str.search(reg))
// 返回 7
複製代碼
1.身份證號碼
舉個身份證的例子: 110105199109214237
由此分析前6位是數字地區區號組成,而後四位是年,兩位月,兩位日和四位隨機,倒數第二位單數男性,雙數女性,最後一位多是大寫X,因此根據這個規則的正則是
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.郵箱
舉個郵箱的例子:weiran@vipkid.com.cn
由此分析:
1.@前面多是數字、字母、下劃線、-、. 2.-和.不能相連在一塊兒
/^\w+((-|\w+)|(.\w+))*/ 開頭必定是數字,字母或下劃線組成,後面的內容多是-與數字字母下劃線 或者.和數字字母下劃線組成的0到多個字符
3.@後面部分
首先必定是數字字母組成的多位字符
而後可能存在是.組成的郵箱後綴或者連接前方字符的.和-
最後確定是.組成的郵箱後綴
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截取
舉個截取url參數的例子:
www.ngaiwe.com/page/index.…
咱們想要的是參數轉化鍵值對和哈希值{name: 'weiran',age: 27, sex: 0, HASH: 'develpoment'}
由此分析:
須要分爲兩部分捕獲,首先第一次捕獲?後面的參數,第二次捕獲#後面的hash值
首先匹配第一個,他的規則是匹配等號兩邊因此是/()=()/,而且匹配的是非?&=#的特殊字符,將他們保存在obj對象中
其次匹配hash,方法和第一個相似只是匹配#後面的部分
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
}
複製代碼
具體案例就就少到這裏,網上有各類正則的案例,同窗們之後看到案例具體分析他們是如何寫的,不要一味地使用,這樣才能在工做中不斷地思考,學習。
有任何問題可留言或者發送本人郵箱ngaiwe@126.com