一、匹配次數中的貪婪與非貪婪
在使用修飾匹配次數的特殊符號時,有幾種表示方法可以使同一個表達式能夠匹配不同的次數,比如:"{m,n}", "{m,}", "?", "*", "+",具體匹配的次數隨被匹配的字符串而定。這種重復匹配不定次數的表達式在匹配過程中,總是盡可能多的匹配。比如,針對文本 "dxxxdxxxd",舉例如下:
表達式 |
匹配結果 |
"/w+" 將匹配第一個 "d" 之后的所有字符 "xxxdxxxd" |
|
"/w+" 將匹配第一個 "d" 和最后一個 "d" 之間的所有字符 "xxxdxxx"。雖然 "/w+" 也能夠匹配上最后一個 "d",但是為了使整個表達式匹配成功,"/w+" 可以 "讓出" 它本來能夠匹配的最后一個 "d" |
由此可見,"/w+" 在匹配的時候,總是盡可能多的匹配符合它規則的字符。雖然第二個舉例中,它沒有匹配最后一個 "d",但那也是為了讓整個表達式能夠匹配成功。同理,帶 "*" 和 "{m,n}" 的表達式都是盡可能地多匹配,帶 "?" 的表達式在可匹配可不匹配的時候,也是盡可能的 "要匹配"。這 種匹配原則就叫作 "貪婪" 模式 。
非貪婪模式:
在修飾匹配次數的特殊符號后再加上一個 "?" 號,則可以使匹配次數不定的表達式盡可能少的匹配,使可匹配可不匹配的表達式,盡可能的 "不匹配"。這種匹配原則叫作 "非貪婪" 模式,也叫作 "勉強" 模式。如果少匹配就會導致整個表達式匹配失敗的時候,與貪婪模式類似,非貪婪模式會最小限度的再匹配一些,以使整個表達式匹配成功。舉例如下,針對文本 "dxxxdxxxd" 舉例:
表達式 |
匹配結果 |
"/w+?" 將盡可能少的匹配第一個 "d" 之后的字符,結果是:"/w+?" 只匹配了一個 "x" |
|
為了讓整個表達式匹配成功,"/w+?" 不得不匹配 "xxx" 才可以讓后邊的 "d" 匹配,從而使整個表達式匹配成功。因此,結果是:"/w+?" 匹配 "xxx" |
更多的情況,舉例如下:
舉例1:表達式 "<td>(.*)</td>" 與字符串 "<td><p>aa</p></td> <td><p>bb</p></td>" 匹配時,匹配的結果是:成功;匹配到的內容是 "<td><p>aa</p></td> <td><p>bb</p></td>" 整個字符串, 表達式中的 "</td>" 將與字符串中最后一個 "</td>" 匹配。
舉例2:相比之下,表達式 "<td>(.*?)</td>" 匹配舉例1中同樣的字符串時,將只得到 "<td><p>aa</p></td>", 再次匹配下一個時,可以得到第二個 "<td><p>bb</p></td>"。
首先我們以簡單的例子來說說什么是正則表達式的貪婪與非貪婪匹配?
比如假定匹配字符串和正則表達式為:
1、貪婪匹配
let res = /ab.*c/
'abcdefc'.match(res) // ["abcdefc", index: 0, input: "abcdefc", groups: undefined]
正則表達式一般趨向於最大長度匹配,總是嘗試匹配盡可能多的字符,也就是所謂的貪婪匹配。如上面使用模式p匹配字符串str,結果就是匹配到:abcdefc。當出現c時,它還是繼續向后找,又找到c,它就把cdef當做是(.*)的匹配
2、非貪婪匹配
let res = /ab.*?c/
'abcdefc'.match(res) // ["abc", index: 0, input: "abcdefc", groups: undefined]
非貪婪匹配就是匹配到結果就好,總是嘗試匹配盡可能少的字符。如上面使用模式p匹配字符串str,結果就是匹配到:abc。當它遇見c后,它就停止查找,此時把空字符作為(.*)的匹配。
3、貪婪匹配與非貪婪匹配如何區分
默認是貪婪模式;在量詞后面直接加上一個問號?就是非貪婪模式。
我們熟知的量詞有:
* |
任意多個 |
+ |
至少一個 |
? |
0或1個 |
{m,n} |
m到n個 |
比如在去除HTML中的標簽時,我們使用 '<.+>' 去匹配得到的卻是一堆'\n',我們來看看原因。拿其中的一行 <p><br/></p> 來看,為什么輸出'\n':
let _html1 = `<p><br/></p>
<p><br/></p>
<p><br/></p>` let res = /<.+>/g _html1.replace(res, '') "
"
在匹配操作時,首先匹配 <(左尖括號),<p>的<就已經匹配到,當匹配到<p>的>時,匹配未結束,它繼續往后匹配。當匹配到<br/>的>時,仍然未結束,貪婪的向后繼續匹配,直到匹配到</p>的>,再繼續去匹配,字符串后面有個‘\n',結束匹配,它就把 p><br/></p 這些內容都當做 .+ 來處理。因此匹配到這一行內容除了'\n',並進行替換操作,替換為空字符'',因此輸出'\n'。因此,在 .+ 后面加上?表示非貪婪模式,當碰到<p>的 > 就停止此次匹配。
let res = /<.+>/
'<p><br/></p>'.match(res) // ["<p><br/></p>", index: 0, input: "<p><br/></p>", groups: undefined]
let res = /<.+?>/
'<p><br/></p>'.match(res) // ["<p>", index: 0, input: "<p><br/></p>", groups: undefined]
二、常用方法
1、exec():一個在字符串中執行查找匹配的RegExp方法,它返回一個數組(未匹配到則返回null)
var reg1= /^\w+$/
var str = 'w111fafdd' console.log(reg1.exec(str)) // ["w111fafdd", index: 0, input: "w111fafdd", groups: undefined]
- 跟match的結果有點像,但是match匹配到多個時可以返回一個滿足匹配規則所有字符串的數組
- 第一個參數是返回能夠匹配正則規則的字符串,則案例的非特殊字符
- input屬性的值是原來的字符串,即str
- 結果的index表示從第幾個字符串開始匹配到的
2、test():一個在字符串中測試是否匹配的RegExp方法,它返回true或false
// 接上面代碼
console.log(reg1.test(str)) // true
3、search():一個在字符串中測試匹配的String方法,它返回匹配到的位置索引,或者在失敗時返回-1。
// 接着上面代碼
console.log(str.search(reg1)) // 0
4、match():一個在字符串中執行查找匹配的String方法,它返回一個數組或者在未匹配到時返回null。
console.log(str.match(reg1)) //["w111fafdd", index: 0, input: "w111fafdd", groups: undefined]
跟上面exec除了調用的對象和參數不同,結果是一樣,當一個字符串多個能匹配正則表達式規則時,match返回是不同的
看一下這2個區別
var reg1= /[a-z]\d{3}/g var str = 'w111faf222dd' reg1.exec(str) // ["w111", index: 0, input: "w111faf222dd", groups: undefined]
var reg1 = /[a-z]\d{3}/g var str = 'w111faf222dd' str.match(reg1) // (2) ["w111", "f222"]
案例:提取工資
需求:var str = ‘張三:1000,李四:5000,王五:8000。’;提取他們三人的工資並返回一個數組
// 方式1:使用提取組的方法
var str = '張三:1000,李四:5000,王五:8000。';
// 寫一個匹配它們的正則表達式
var reg = /(\d+)/g // 使用數組用來裝他們
var arr = [] while(reg.test(str)){ arr.push(RegExp.$1) //$1是提取第一個組的意思,如果上面的正則表達式的括號沒加,則提取是空的字符串,因為沒有分組
} console.log(arr) //["1000", "5000", "8000"]
// 我們可以使用一個match就可以搞定了
var str = '張三:1000,李四:5000,王五:8000。'; var reg = /\d+/g console.log(str.match(reg)) // ["1000", "5000", "8000"]
5、replace():一個在字符串中執行查找匹配的String方法,並且使用替換字符串替換掉匹配到的子字符串
1)str.replace(parame1,parame2);就是將parame1替換成parame2
2)去字符串的所有空格
trim()這個方法只能去掉前后的空格,當要去掉字符串所有的空格時,使用replace替換掉所有的空格
var str = " 123AD asadf asadfasf adf "
var str1 = str.replace(/\s+/g,'') console.log(str1) // 123ADasadfasadfasfadf
6、split():一個使用正則表達式或者一個固定字符串分隔一個字符串,並將分隔后的子字符串存儲到數組中的String方法
1)我們之前使用split()時大部分是將字符串切割為數組,括號跟着的是一個字符串
var dateStr = '2015-1-5'; var arr = dateStr.split('-') console.log(arr) // ["2015", "1", "5"]
2)參數為正則表達式
var dateStr = '2015-12&23,78' dateStr.split(/[-&,]/) // (4) ["2015", "12", "23", "78"]
以上的所有方法並不會改變調用它的字符串 | 正則表達式,記得它們如何使用和返回值即可。