JavaScript 正則表達式

定義

JavaScript種正則表達式有兩種定義方式,定義一個匹配相似 <%XXX%> 的字符串html

1. 構造函數前端

var reg=new RegExp('<%[^%>]+%>','g');

2. 字面量正則表達式

var reg=/<%[^%>]%>/g;
  • g: global,全文搜索,默認搜索到第一個結果就中止
  • i: ingore case,忽略大小寫,默認大小寫敏感
  • m: multiple lines,多行搜索(更改^ 和$的含義,使它們分別在任意一行對待行首和行尾匹配,而不只僅在整個字符串的開頭和結尾匹配)

元字符

正則表達式讓人望而卻步以一個重要緣由就是其轉義字符太多了,組合很是之多,可是正則表達式的元字符(在正則表達式中具備特殊意義的專用字符,能夠用來規定其前導字符)並很少數組

元字符:( [ { \ ^ $ | ) ? * + .ruby

並非每一個元字符都有其特定意義,在不一樣的組合中元字符有不一樣的意義,分類看一下函數

預約義特殊字符

字符 含義
\t 水平製表符
\r 回車符
\n 換行符
\f 換頁符
\cX 與X對應的控制字符(Ctrl+X)
\v 垂直製表符
\0 空字符

 

 

 

 

 

 

 

字符類

通常狀況下正則表達式一個字符(轉義字符算一個)對應字符串一個字符,表達式 ab\t 的含義是測試

可是咱們可使用元字符[]來構建一個簡單的類,所謂類是指,符合某些特徵的對象,是一個泛指,而不是特指某個字符了,咱們可使用表達式 [abc] 把字符a或b或c歸爲一類,表達式能夠匹配這類的字符spa

元字符[]組合能夠建立一個類,咱們還可使用元字符^建立反向類/負向類,反向類的意思是不屬於XXX類的內容,表達式 [^abc] 表示不是字符a或b或c的內容3d

範圍類

按照上面的說明要是咱們但願匹配單個數字那麼表達式是這樣的code

[0123456789]

若是是字母那麼。。。,好麻煩,正則表達式還提供了範圍類,咱們可使用 x-y來鏈接兩個字符表示從x到y的任意字符,這是個閉區間,也就是說包含x和y自己,這樣匹配小寫字母就很簡單了

[a-z]

要是想匹配全部字母呢?在[]組成的類內部是能夠連寫的,咱們還能夠這樣寫 [a-zA-Z]

預約義類

剛纔使用正則咱們建立了幾個類,來表示數字,字母等,但這樣寫也非常麻煩,正則表達式爲咱們提供了幾個經常使用的預約義類來匹配常見的字符

字符 等價類 含義
. [^\n\r] 除了回車符和換行符以外的全部字符
\d [0-9] 數字字符
\D [^0-9] 非數字字符
\s [ \t\n\x0B\f\r] 空白符
\S [^ \t\n\x0B\f\r] 非空白符
\w [a-zA-Z_0-9] 單詞字符(字母、數字、下劃線)
\W [^a-zA-Z_0-9] 非單詞字符

 

 

 

 

 

 

 

 

有了這些預約義類,寫一些正則就很方便了,好比咱們但願匹配一個 ab+數字+任意字符 的字符串,就能夠這樣寫了 ab\d.

 

邊界

正則表達式還提供了幾個經常使用的邊界匹配字符

字符

含義

^

以xx開頭

$

以xx結尾

\b

單詞邊界,指[a-zA-Z_0-9]以外的字符

\B

非單詞邊界

 

 

 

 

 

 

 

 

看個不負責任的郵箱正則匹配(切勿模仿,小括號後面會講到) \w+@\w+\.(com)$

量詞

以前咱們介紹的方法都是一一匹配的,若是咱們但願匹配一個連續出現20次數字的字符串難道咱們須要寫成這樣

\d\d\d\d...

爲此正則表達式引入了一些量詞

字符 含義
? 出現零次或一次(最多出現一次)
+ 出現一次或屢次(至少出現一次)
* 出現零次或屢次(任意次)
{n} 出現n次
{n,m} 出現n到m次
{n,} 至少出現n次
   

 

 

 

 

 

 

 

 

看幾個使用量詞的例子

\w+\b Byron 匹配 單詞+邊界+Byron

 

(/\w+\b Byron/).test('Hi Byron'); //true

(/\w+\b Byron/).test('Welcome Byron'); //true

(/\w+\b Byron/).test('HiByron'); //false

 \d+\.\d{1,3} 匹配三位小數的數字

 貪婪模式與非貪婪模式

看了上面介紹的量詞,也許愛思考的同窗會想到關於匹配原則的一些問題,好比{3,5}這個量詞,要是在句子種出現了十次,那麼他是每次匹配三個仍是五個,反正三、四、5都知足3~5的條件,量詞在默認下是儘量多的匹配的,也就是你們常說的貪婪模式

'123456789'.match(/\d{3,5}/g); //["12345", "6789"] 

 既然有貪婪模式,那麼確定會有非貪婪模式,讓正則表達式儘量少的匹配,也就是說一旦成功匹配不再也不繼續嘗試,作法很簡單,在量詞後加上 ? 便可

'123456789'.match(/\d{3,5}?/g); //["123", "456", "789"]

 分組

有時候咱們但願使用量詞的時候匹配多個字符,而不是像上面例子只是匹配一個,好比但願匹配Byron出現20次的字符串,咱們若是寫成 Byron{20} 的話匹配的是Byro+n出現20次,怎麼把Byron做爲一個總體呢?使用()就能夠達到次目的,咱們稱爲分組

(Byron){20}

 

 若是但願匹配Byron或Casper出現20次該怎麼辦呢?可使用字符 | 達到或的功效

(Byron|Casper){20}

 

 咱們看到圖中有個#1的東東,那是什麼?使用分組的正則表達式會把匹配項也放到分組中,默認就是按數字編號分發的,各異根據編號得到捕獲的分組內容,這個在一些但願具體操做第幾個匹配項的函數中頗有用

(Byron).(ok)

 

若是有分組嵌套的狀況,外面的組的編號靠前

((^|%>)[^\t]*)

 

有時候咱們不但願捕獲某些分組,只須要在分組內加上 ?: 就能夠了,着並不意味着該分組內容不屬於正則表達式,只是不會給這個分組加編號了而已

(?:Byron).(ok)

 

 其實在C#等語言中分組還能夠起名字,不過JavaScript不支持

前瞻

表達式 含義
exp1(?=exp2) 匹配後面是exp2的exp1
exp1(?!exp2) 匹配後面不是exp2的exp1

 

 

 

 

說的有些抽象,看個例子 good(?=Byron)

(/good(?=Byron)/).exec('goodByron123'); //['good']
(/good(?=Byron)/).exec('goodCasper123'); //null
(/bad(?=Byron)/).exec('goodCasper123');//null

經過上面例子能夠看出 exp1(?=exp2) 表達式會匹配exp1表達式,但只有其後面內容是exp2的時候纔會匹配,也就是兩個條件,exp1(?!exp2) 比較相似

good(?!Byron)

(/good(?!Byron)/).exec('goodByron123'); //null
(/good(?!Byron)/).exec('goodCasper123'); //['good']
(/bad(?!Byron)/).exec('goodCasper123');//null

 


 

 

上面介紹了JavaScript正則表達式的語法,有了這些基本知識,能夠看看正則表達式在JavaScript的應用了,在一切開始以前,看看RegExp實例的幾個屬性

 

RegExp實例對象有五個屬性

  1. global:是否全局搜索,默認是false
  2. ignoreCase:是否大小寫敏感,默認是false
  3. multiline:多行搜索,默認值是false
  4. lastIndex:是當前表達式模式首次匹配內容中最後一個字符的下一個位置,每次正則表達式成功匹配時,lastIndex屬性值都會隨之改變。
  5. source:正則表達式的文本字符串

 除了將正則表達式編譯爲內部格式從而使執行更快的compile()方法,對象還有兩個咱們經常使用的方法

regObj.test(strObj)

方法用於測試字符串參數中是否存正則表達式模式,若是存在則返回true,不然返回false

複製代碼
var reg=/\d+\.\d{1,2}$/g;

reg.test('123.45'); //true
reg.test('0.2'); //true

reg.test('a.34'); //false
reg.test('34.5678'); //false
複製代碼

regObj.exec(strObj)

方法用於正則表達式模式在字符串中運行查找,若是 exec() 找到了匹配的文本,則返回一個結果數組。不然,返回 null。除了數組元素和 length 屬性以外,exec() 方法還返回兩個屬性。index 屬性聲明的是匹配文本的第一個字符的位置。input 屬性則存放的是被檢索的字符串 string。

調用非全局的 RegExp對象的 exec() 時,返回數組的第 0 個元素是與正則表達式相匹配的文本,第 1 個元素是與 RegExpObject 的第 1 個子表達式相匹配的文本(若是有的話),第 2 個元素是與 RegExp對象的第 2 個子表達式相匹配的文本(若是有的話),以此類推。

調用全局的RegExp對象的 exec() 時,它會在 RegExp實例的 lastIndex 屬性指定的字符處開始檢索字符串 string。當 exec() 找到了與表達式相匹配的文本時,在匹配後,它將把 RegExp實例的 lastIndex 屬性設置爲匹配文本的最後一個字符的下一個位置。能夠經過反覆調用 exec() 方法來遍歷字符串中的全部匹配文本。當 exec() 再也找不到匹配的文本時,它將返回 null,並把 lastIndex 屬性重置爲 0。

var reg=/\d/g;
var r=reg.exec('a1b2c3'); 
console.log(reg.lastIndex); //2
r=reg.exec('a1b2c3');
console.log(reg.lastIndex); //4

兩次執行r的結果

           

var reg=/\d/g;
while(r=reg.exec('a1b2c3')){
    console.log(r.index+':'+r[0]);
}
能夠看到結果:
1:1
3:2
5:3

除了上面的兩個方法,有些字符串函數能夠傳入RegExp對象做爲參數,進行一些複雜的操做

strObj.search(RegObj)

search() 方法用於檢索字符串中指定的子字符串,或檢索與正則表達式相匹配的子字符串。search() 方法不執行全局匹配,它將忽略標誌 g。它同時忽略 regexp 的 lastIndex 屬性,而且老是從字符串的開始進行檢索,這意味着它老是返回 stringObject 的第一個匹配的位置。

'a1b2c3'.search(/\d/g); //1
'a1b2c3'.search(/\d/); //1

strObj.match(RegObj)

match() 方法將檢索字符串 stringObject,以找到一個或多個與 regexp 匹配的文本。但regexp是否具備標誌 g對結果影響很大。

若是 regexp 沒有標誌 g,那麼 match() 方法就只能在 strObj 中執行一次匹配。若是沒有找到任何匹配的文本, match() 將返回 null。不然,它將返回一個數組,其中存放了與它找到的匹配文本有關的信息。該數組的第 0 個元素存放的是匹配文本,而其他的元素存放的是與正則表達式的子表達式匹配的文本。除了這些常規的數組元素以外,返回的數組還含有兩個對象屬性。index 屬性聲明的是匹配文本的起始字符在 stringObject 中的位置,input 屬性聲明的是對 stringObject 的引用。

var r='aaa123456'.match(/\d/); 

若是 regexp 具備標誌 g,則 match() 方法將執行全局檢索,找到 strObj 中的全部匹配子字符串。若沒有找到任何匹配的子串,則返回 null。若是找到了一個或多個匹配子串,則返回一個數組。不過全局匹配返回的數組的內容與前者大不相同,它的數組元素中存放的是 strObj 中全部的匹配子串,並且也沒有 index 屬性或 input 屬性。

var r='aaa123456'.match(/\d/g);

strObj.replace(regObj,replaceStr)

關於strng對象的replace方法,咱們最經常使用的時傳入兩個字符串的作法,但這種作法有個缺陷,只能replace一次

'abcabcabc'.replace('bc','X'); //aXabcabc

replace方法的第一個參數還能夠傳入RegExp對象,傳入正則表達式能夠時replace方法更增強大靈活

'abcabcabc'.replace(/bc/g,'X'); //aXaXaX
'abcaBcabC'.replace(/bc/gi,'X'); //aXaXaX

若是replace方法的第一個參數傳入的是帶分組的正則表達式,咱們在第二個參數中可使用$1...$9來獲取相應分組內容,好比但願把字符串 1<%2%>34<%567%>89 的<%x%>換爲$#x#$,咱們能夠這樣

'1<%2%>34<%567%>89'.replace(/<%(\d+)%>/g,'@#$1#@');
//"1@#2#@34@#567#@89"

固然還有不少方式能夠達到這一目的,這裏只是演示一下利用分組內容,咱們在第二個參數中使用 @#$1#@,其中$1表示被捕獲的分組內容,在一些js模板函數中能夠常常見到這種方式替換字符串。

strObj.replace(regObj,function(){})

能夠經過修改replace方法的第二個參數,使replace更增強大,在前面的介紹中,只能把全部匹配替換爲固定內容,但若是我但願把一個字符串中全部數字,都用小括號包起來該怎麼弄

'2398rufdjg9w45hgiuerhg83ghvif'.replace(/\d+/g,function(r){
    return '('+r+')';
}); //"(2398)rufdjg(9)w(45)hgiuerhg(83)ghvif"

把replace方法的第二個參數傳入一個function,這個function會在每次匹配替換的時候調用,算是個每次替換的回調函數,咱們使用了回調函數的第一個參數,也就是匹配內容,其實回調函數一共有四個參數

  1. 第一個參數很簡單,是匹配字符串
  2. 第二個參數是正則表達式分組內容,沒有分組則沒有該參數
  3. 第三個參數是匹配項在字符串中的index
  4. 第四個參數則是原字符串
複製代碼
'2398rufdjg9w45hgiuerhg83ghvif'.replace(/\d+/g,function(a,b,c){
    console.log(a+'\t'+b+'\t'+c);
    return '('+a+')';
}); 

2398    0    2398rufdjg9w45hgiuerhg83ghvif
9    10    2398rufdjg9w45hgiuerhg83ghvif
45    12    2398rufdjg9w45hgiuerhg83ghvif
83    22    2398rufdjg9w45hgiuerhg83ghvif 
複製代碼

這是沒有分組的狀況,打印出來的分別是 匹配內容、匹配項index和原字符串,看個有分組的例子,若是咱們但願把一個字符串的<%%>外殼去掉,<%1%><%2%><%3%> 變成123

複製代碼
'<%1%><%2%><%3%>'.replace(/<%([^%>]+)%>/g,function(a,b,c,d){
    console.log(a+'\t'+b+'\t'+c+'\t'+d);
    return b;
}) //123

<%1%>    1    0    <%1%><%2%><%3%> 
<%2%>    2    5    <%1%><%2%><%3%> 
<%3%>    3    10    <%1%><%2%><%3%> 
複製代碼

根據這種參數replace能夠實現不少強大的功能,尤爲是在複雜的字符串替換語句中常用。

strObj.split(regObj)

咱們常用split方法把字符串分割爲字符數組

'a,b,c,d'.split(','); //["a", "b", "c", "d"]

和replace方法相似,在一些複雜的分割狀況下咱們可使用正則表達式解決

'a1b2c3d'.split(/\d/); //["a", "b", "c", "d"]

這樣就能夠按照數字分割字符串了,是否是很強大。看完這兩篇博客基本就能對平時用到的JavaScript正則表達式遊刃有餘了。要求在前端把一個div中的英文段落單詞首字母都換成大寫,你是否是知道該怎麼作了?

參考 

司徒正美 JavaScript正則表達式

Regexper

相關文章
相關標籤/搜索