正則表達式-基礎知識Review

正則表達式-基礎知識Review

正則表達式(Regular Expression)是計算機科學的一個概念。 正則表達式使用單個字符竄來描述、匹配一系列符合某個句法規則的字符竄。 在不少文本編輯器裏, 正則表達式一般用來被檢索替換哪些符合某個模式的文本。正則表達式

建立

JavaScript經過內置對象 RegExp支持正則表達式, 有兩種方式建立正則表達式對象, 若是咱們想匹配字符竄中<%xxx%>兩個百分號分割的字符竄能夠這麼寫。數組

  • 構造函數
var regExp = new RegExp('<%[^%>]+%', 'g');
  • 字面量
var regExp = /<%[^%>]%>/g;

最後的g表明全局, 還有幾個修飾符編輯器

RegExp實例對象有五個屬性函數

  1. g: global, 全文搜索,不添加的話搜索到第一個結果中止搜索。
  2. i: ignore case, 忽略大小寫,默認大小寫敏感。
  3. m: multiple lines, 多行搜索。
  4. lastIndex: 是當前表達式模式首次匹配內容中最後一個字符的下一個位置,每次正則表達式匹配成功匹配時, lastIndex屬性值都會隨之改變。
  5. sourse:正則表達式的文本字符竄。

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

元字符

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

() [] {} \ ^ $ | ? * + .

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

  • t 水平製表符 tab
  • r 回車符 carriage return
  • n 換行符 newline
  • f page feed 換頁符
  • cX 與X對應的控制字符(Ctrl + X )
  • v 垂直製表符
  • 0 空字符

字符類

通常狀況下正則表達式一個字符(轉譯字符算一個) 對應字符竄一個字符,表達式 abt 的含義3d

ab水平製表符

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

字符類取反

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

範圍類

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

[0123456789]

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

[a-z]

預約義類

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

字符 等價類 含義
. [^rt] 除了回車符和換行符以外的全部字符
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 + 數字 + 任意字符的字符竄, 就能夠寫了abd.

能夠把正則表達式,想象成一種模式,字符竄匹配正則表達式定義的模式的結果

string.match(regExpPattern)

邊界

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

字符 含義
^ 以xxx開頭, ^ 開頭的匹配參照對象是整個字符竄
$ 以xxx結尾, $ 結尾的匹配參照對象也是整個字符竄
b 單詞邊界, '-'也是單詞邊界!
B 非單詞邊界
^ 開頭的匹配參照對象是整個字符竄,
$ 結尾的匹配參照對象也是整個字符竄,
限制的是整個字符竄。

var regExpPattern = /^h\dm/g;
'h2m h4m h2m'.match(regExpPattern); // h2m, 記住這是以整個字符竄去匹配的

//同理

var regExpExpPattern = /h\dm$/g;
'h2m h4m h4m'.match(regExpPattern); // h4m

//使用場景 手機號匹配

'13423454234'.match(/^1\d{10}$/g)

量詞

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

\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d..

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

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

regExp.test('hi Bryon'); // true

regExp.test('Welcome Byron'); // true

regExp.test('Byron'); //false


//匹配帶有3到1個小數的數字
var reg = /\d+\.d{1,3}

貪婪模式與非貪婪模式

看了量詞的介紹,也許愛思考的同窗會想到關於匹配原則的一些問題, 好比{3,5} 這個量詞, 要是在句子中出現了十次, 那麼他是每次匹配三個仍是五個,反正3,4,5都知足3~5的條件。

量詞在默認下是儘量多的匹配的,也就是你們常說的貪婪模式。

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

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

//['123','456','789']

'123456789'.match(/\d{3,5}?/g);

分組

有時候但願使用量詞的時候匹配多個字符,而不是像上面例子只是匹配一個,好比但願匹配Byron出現20次的字符竄,寫成Byron{20}的話匹配的是Byro+n出現20次。

//寫成Byron{20}的話匹配的是Byro+n出現20次。
/Byron{20}/g

怎麼把Byron做爲一個總體呢? 使用()就能夠達到此目的,在正則中成爲分組。

//分組在regExp.exec(stringObj)中會單獨顯示在返回結果中。

(Byron){20}

或 |

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

(Byron|Casper){20}

使用分組的正則表達式會把匹配項也放到分組中,默認是按數字編號分發的,能夠根據編號得到捕獲的分組內容,這在一些但願具體操做第幾個匹配項的函數中頗有用。

// Group 1 : Byron , Group 2: ok
(Byron).(ok)

分組嵌套

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

// group 1: (^|%>)[^\t]*, Group 2: (^|%>)
((^|%>)[^\t]*)

忽略分組

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

(?:Bryon).(ok)

前瞻

表達式 含義
exp1(?=exp2) 匹配後面是exp2的exp1
exp1(?!exp2) 匹配後面不是exp2的exp1
var regExp = /good(?=Byron)/;

regExp.exec('goodByron123'); // ['good']
regExp.exec('goodCapser123'); // null

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

正則表達式相關的方法

  • RegExp.prototype.test(str)

該方法用於測試字符竄參數中是否匹配正則表達式模式,若是存在則返回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
//判斷手機號是否正確
function isPhoneNum(phoneNum) {
    var phoneNumberTester = /^1\d{10}$/;
    return phoneNumberTester.test(phoneNum);
}
  • RegExp.prototype.exec(str)

該方法用於正則表達式模式在字符竄中運行查找,若是exec()找到匹配的文本,則返回一個結果,不然返回null

除了數組元素和length屬性以外, exec()方法返回對象還包括兩個屬性。

  1. index屬性聲明的是匹配文本的第一個字符的位置。
  2. input屬性則存放的是被檢索的字符竄string。

非全局調用

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

全局調用

調用全局的RegExp對象的exec()時,它會在RegExp實例的lastIndex屬性指定的字符處開始檢索字符竄string

  1. 當exec()找到了與表達式相匹配的文本時, 在匹配後, 它將把RegExp實例的lastIndex屬性設置爲匹配文本的最後一個字符的下一個位置。能夠經過反覆調用exec()方法來遍歷字符竄中的全部哦匹配文本。
  2. 當exec()再也找不到匹配的文本時,它將返回null,並把lastIndex屬重置爲0。
var reg = /\d/g;

var r =  reg.exec('a1b2c3');

console.log(r);

console.log(reg.lastIndex); // 2

r = reg.exec('a1b2c3');

console.log(reg.lastIndex); // 4
var reg = /\d/g;

while (r = reg.exec('a1b2c3')) {
    console.log(r.index + ':' + r[0])
}

//1:1 , 3:2, 5:3
  • String.prototype.search(reg)

search()方法用於檢索字符竄中指定的子字符串,或檢索與正則表達式相匹配的子字符竄。

search()方法不執行全局匹配,它將忽略標誌g, 它同時忽略正則表達式對象的lastIndex屬性,而且老是從字符竄的開始進行檢索,這意味着它老是返回字符竄的第一個匹配的位置。

  • String.prototype.match(reg)

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

非全局調用

若是regexp沒有標誌g,那麼match()方法就只能在字符竄中執行一次匹配。若是沒有找到任何匹配的文本,match()將返回null。不然它將返回一個數組,其中存放了與它找到的匹配文本有關的信息。

該數組的第一個元素存放的是匹配文本,而其他的元素存放的是與正則表達式的子表達式匹配的文本。除了這些常規的數組元素以外,返回的數組還含有兩個對象屬性。

  1. index屬性聲明的是匹配文本的起始字符在字符竄中的位置。
  2. input屬性聲明的是對stringObject的引用。
  • String.prototype.replace(reg, replaceStr|| function callback())

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

'abcabcabc'.replacce('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%>換爲&dollar;#x#$, 咱們能夠這樣

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

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

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

'2398sdadads1smdsa3mmm23mmmbb'.replace(/\d+/g, function(matchedStr, groupContent$, index, strObj ) {
    return '(' + matchedStr + ')';
})

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

  • 第一個參數很簡單,是匹配字符竄。
  • 第二個參數是正則表達式分組內容,沒有分組則沒有該參數。
  • 第三個參數是匹配項在字符竄中的index。
  • 第四個參數則是原字符竄。

例子

'2398rsjdhahd2131kksdajdj23'.replace(/\d+/g, function(matchedSubStr,index, strObj) {
    console.log(matchedSubStr + '\t' + index + '\t' + strObj);
    return '(' + matchedSubStr +')';
})

//2398 0    2398rsjdhahd2131kksdajdj23    
//2131 12    2398rsjdhahd2131kksdajdj23    
//23 24 2398rsjdhahd2131kksdajdj23

這是沒有分組的狀況,打印出來的分別是匹配內容、匹配項index和原字符竄,看個有分組的。

'<%1%><%2%><%3%>'.replace(/<%([^%>]+)%>/g, function(matchedStr, group, index, thisStrObj) {
    console.log(matchedStr + '\t' + group + '\t' + index + '\t' + thisStrObj);
    return group;
})

//<%1%>    1    0    <%1%><%2%><%3%>
//<%2%>    2    5    <%1%><%2%><%3%>
//<%3%>    3    10    <%1%><%2%><%3%>
//"123"
  • String.prototype.split(reg)

使用split方法把字符竄分割爲字符數組

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

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

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

  1. abc
相關文章
相關標籤/搜索