JavaScript中的正則表達式

文章同步到githubjava

正則在平時工做中用的很是多, 最開始接觸正則的時候感受這個東東好難記啊,最近把正則的內容整理了一下,寫成如下文章。git

先給你們介紹一個在線解析正則的網站,來幫助咱們理解正則,特別是複雜的正則表達式,很是好用github

http://www.regexper.com正則表達式

好比/^@[a-zA-Z]d+@$/,解析以後圖形幫助理解以下:數組

reg解析

什麼是正則

正則表達式是用於匹配字符串中字符組合的模式。主要應用於正則對象的test和esec方法,以及字符串的search、split、match、replace中。app

建立正則

字面量建立

var reg = /pattern/flag;

每一個正則表達式均可以帶有一個或多個(也能夠不帶)代表正則表達式行爲的標誌函數

正則flag

構造函數建立

在js中提供了一個內置構造函數RegExp來建立一個正則對象工具

var reg =  new RegExp(pattern [, flags]);
var reg = /[ab]c/g;
// 等價於
var reg = new RegExp("[ab]c", "g");

正則表達式中的特殊字符

元字符

元字符是在正則表達式中有特殊含義的非字母字符,js中正則表達式元字符包括:

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

由於這些字符在正則表達式中具備特殊含義,因此若是要想在字符串中匹配這些字符,就必須對它們進行轉義.this

// 匹配字符串中的ac或者bc
var reg = /[ab]c/;

// 若是要匹配字符串的"[ab]c", 須要對[]進行轉義
var reg = /\[ab\]c/;

注意:
另外須要注意的是,因爲使用構造函數建立正則,pattern參數必須爲字符串,全部元字符若是須要在字符串中匹配這個字符,須要進行雙重轉義

var reg = /\[ab\]c/g;

若是使用構造函數建立正則表達式,應該寫成:

var reg = new RegExp("\\[ab\\]c", "g");

字符集合

咱們可使用[]來構建一個簡單的類[xyz],類指符合某些特性的對象,是一個泛指,並非指某個字符,表示匹配方括號的中任意字符,對於點(.)和星號(*)這樣的特殊符號在一個字符集中沒有特殊的意義。他們沒必要進行轉義,不過轉義也是起做用的。

字符 含義
[xyz] 匹配方括號的中任意字符
var reg = /[abc]/g;
var reg2 = /[abc.]/g;  // 字符集合中的.
var reg3 = /[abc\.]/g;  // 字符集合中轉義的.

var str = 'a1b2c3';
var str2 = 'a1b2c3d.';

var res = str.replace(reg, 'X');
var res2 = str2.replace(reg2, 'X');
var res3 = str3.replace(reg3, 'X');

console.log(res);  //  X1X2X3
console.log(res2);  //  X1X2X3dX
console.log(res3);  //  X1X2X3dX

字符集合取反

字符 含義
[^xyz] 匹配任何沒有包含在方括號中的字符
var reg = /[^abc]/g;
var str = 'abcdefg';
var res = str.replace(reg, 'X');
console.log(res);  //  abcXXXX

範圍類

在字符集合中可使用(-)來指定一個字符範圍, 如[a-z],表示匹配從a到z的任意字符

var reg = /[a-z]/g;
var str = 'a1b2c3d4e5F6';
var res = str.replace(reg, 'X');
console.log(res); //  X1X2X3X4X5F6

在範圍類[]中能夠連寫,如同時匹配大小寫,[a-zA-Z]

var reg = /[a-zA-Z]/g;
var str = 'a1b2c3d4e5F6';
var res = str.replace(reg, 'X');
console.log(res); //  X1X2X3X4X5X6

預約義類

正則表達式提供了預約義類,來匹配常見的字符類,不須要都經過字符集合去定義正則表達式

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

邊界

正則還提供了邊界匹配符

字符 含義
^ 匹配輸入的開始
$ 匹配輸入的結尾
\b 單詞邊界
\B 非單詞邊界
// ^的應用
var reg = /^@./g
var str = '@123abc@';
var res = str.replace(reg, 'X');
console.log(res);  // X23abc

// $的應用
var reg2 = /^.@$/g;
var str2 = '@123abc@';
var res2 = str2.replace(reg2, 'X');
console.log(res2);  // 123abX

// \b的應用
var reg3 = /\bis\b/g;
var str3 = 'this is javaScript';
var res3 = str3.replace(reg3, 'X');
console.log(res3); // this X javaScript

正則的m標誌應用

var reg = /^@./g;
var str = `@abc
@123
@XYZ
`
var res = str.replace(reg, 'X');
// 由於即便字符串看上去換行,本質上仍是一些換行符,只有結尾和結束
console.log(res);  //  Xbc
                       @123
                       @XYZ

當正則表達式使用m標誌的時候,在一行文本末尾結束的時候,還會去匹配下一行是否存在與模式匹配的項,例子以下:

var reg = /^@./gm;
var str = `@abc
@123
@XYZ
`
var res = str.replace(reg, 'X');
console.log(res);  //  Xbc
                       X23
                       XYZ

量詞

字符 含義
? 匹配前面一個表達式0次或者1次(至多出現一次)
+ 匹配前面一個表達式1次或者屢次(至少出現一次)
* 匹配前一個表達式0次或屢次(任意次)
{n} n是一個正整數,匹配了前面一個字符恰好發生了n次
{n,m} n 和 m 都是整數。匹配前面的字符至少n次,最多m次。若是 n 或者 m 的值是0, 這個值被忽略。
{n,} 匹配前面字符n此或者更屢次(至少出現n次

貪婪模式

貪婪模式是讓正則表達式儘量多的匹配

var reg = /\d{2,5}/;
var str = '12345678';
var res = str.replace(reg, 'X');
console.log(res); // X678

非貪婪模

非貪婪模式是讓正則表達式儘量少的匹配,一旦匹配成功不在繼續匹配,作法是在量詞後面加上?便可

var reg = /\d{2,5}?/
var str = '12345678';
var res = str.replace(reg, 'X');
console.log(res);  // X345678

分組

使用括號()進行分組

量詞不做用於緊挨着的某個字符,使用/(x)/匹配 'x',而且記住匹配項,括號被稱爲補貨括號

var reg = /([a-zA-Z]\d)/g;
var str = 'a1bbc3D4efg';
var res = str.replace(reg, 'X');
console.log(res);  // XbbXXefg

使用在線解析正則工具以下圖:
res正則解析

另外能夠添加量詞

var reg = /(abc){3}/g;
var str = 'abcabcabcabc';
var res = str.replace(reg, 'X');
console.log(res);  // Xabc

使用或' | '進行分組

var reg = /apple|pear/g
var str = 'appleappleHpearpear';
var res = str.replace(reg, 'X');
console.log(res);  // XXHXX

var reg2 = /appl(e|p)ear/g;
var str2 = 'appleearHapplpear'
var res2 = str2.replace(reg2, 'X');
console.log(res2);  // XHX

在線解析上面代碼的reg和reg2以下:
reg:
reg

reg2:
reg2

捕獲匹配到的分組內容

在replace替換環節,可使用$一、$二、$3...$n等捕獲分匹配到的分組

好比想把'25/12/2016'轉換成'2016-12-25':

var reg = /(\d{2})\/(\d{2})\/(\d{4})/;
var str = '25/12/2016';
var res = str.replace(reg, '$3-$2-$1');
console.log(res);  // 2016-12-25

忽略分組

若是不但願捕獲分組,只須要在分組內加上(?:)就能夠

var reg = /(?:\d{2})\/(\d{2})\/(\d{4})/;
var str = '25/12/2016';
var res = str.replace(reg, '$3-$2-$1');

此時$2爲2016,$1爲12,而$3捕獲不到,按普通字符串顯示
console.log(res);  // $3-2016-12

正向確定查找

x(?=y)
匹配x,而且x後必須跟着y,這就是正向確定查找

var reg = /\w(?=\d)/g;
var str = 'a1b2ccd4';
var res = str.replace(reg, 'X');
console.log(res); // X1X2ccX4

正向否認查找

匹配x,而且x後必須不跟着y,這就是正向否認查找

var reg = /[a-z](?!\d)/g;
var str = 'a1b2ccd4';
var res = str.replace(reg, 'X');
console.log(res); // a1b2XXd4

正則對象屬性和方法

屬性

正則對象屬性

屬性皆爲只讀,不可修改

var reg = /\[abc\]/;
console.log(reg.ignoreCase) // false;
console.log(reg.global) // false;
console.log(reg.multiline) // false;

reg.ignoreCase = true;
reg.global = true;
reg.multiline = true;

console.log(reg.ignoreCase) // false;
console.log(reg.global) // false;
console.log(reg.multiline) // false;

仍是以上代碼看一下source屬性

console.log(reg.source) //  \[abc\]

若是使用構造函數建立正則對象,再來看一下source屬性

var reg = new RegExp("\\[abc\\]");  //須要對元字符進行雙重轉義
console.log(reg.source);   // \[abc\]

經過以上對比可知,source屬性是字面量形式建立正則對象全部的字符串

方法

RegExp.prototype.test()

test() 方法執行一個檢索,用來查看正則表達式與指定的字符串是否匹配。匹配到返回 true,不然返回false。

語法

regexObj.test(str)
var reg = /\w/;
var str = 'ab';
console.log(reg.test(str));  // true
console.log(reg.test(str));  // true
console.log(reg.test(str));  // true

注意
當正則表達式使用全局模式時,lastIndex屬性會影響test()方法的返回值,看下面例子

var reg = /\w/g;
var str = 'ab';
console.log(reg.test(str));  // true
console.log(reg.test(str));  // true
console.log(reg.test(str));  // false
console.log(reg.test(str));  // true

爲何會出現這種現象呢,是由於正則表達式執行test方法時,每次都會把結果做用到操做的正則實例上,因爲是全局匹配,第一次匹配到以後reg的lastIndex屬性爲1,繼續匹配,此時從lastIndex的位置開始匹配,即從b開始,結果又匹配到,此時lastIndex屬性爲2,當繼續匹配時,從2開始匹配,沒有匹配到,此時返回false,lastIndex被重置爲0,因此第4次執行console.log(reg.test(str))就會重新從0開始,因此返回值爲true。結合while循環來講明一下:

var reg = /\w/g;
var str = 'ab';
while(reg.test(str)){
    console.log(reg.lastIndex);  // 循環執行兩次,分別打印出1, 2
}

RegExp.prototype.exec()

exec() 方法在一個指定字符串中執行一個搜索匹配.

語法

regexObj.exec(str)

返回值:

1.若是匹配失敗,返回 null。
2.若是匹配成功,exec() 方法返回一個數組,並更新正則表達式對象的屬性,通常來講主要是lastIndex屬性值的更新。返回的數組將徹底匹配成功的文本做爲第一項,將正則括號裏匹配成功的做爲數組填充到後面,返回值雖然是Array實例,可是包含了index和input屬性

index: 表示匹配項在字符串中的位置,也就是匹配項第一個字符的位置
input: 表示應用正則表達式的字符串

非全局調用

返回數組內容包括:

  1. 第一個元素是與正則表達式相匹配的文本
  2. 第二個元素是與正則對象第一個子表達式相匹配的文本,也就是第一個分組(若是有的話)
  3. 第三個元素是與正則對象第二個子表達式相匹配的文本,也就是第而個分組(若是有的話),以此類推
var reg = /\d(\w)(\w)\d/;
var str = '@1bb2c3dd4f';
var res = reg.exec(str);
console.log(reg.lastIndex);  // 0  非全局模式忽略lastIndex屬性
console.log(res.index);  // 1
console.log(res.input);  // @1ab2c3dd4f
console.log(res);  // ["1ab2", "a", "b"]

全局調用

var reg = /\d(\w)(\w)\d/g;
var str = '@1bb2c3dd4f';
var res = reg.exec(str);
console.log(reg.lastIndex);  // 5  非全局模式忽略lastIndex屬性
console.log(res.index);  // 1
console.log(res.input);  // @1ab2c3dd4f
console.log(res);  // ["1ab2", "a", "b"]
console.log(reg.lastIndex);

使用while循環加深一下理解

var reg = /\d(\w)(\w)\d/g;
var str = '@1bb2c3dd4f';
while(reg.exec(str)) {
    console.log(reg.lastIndex, res.index, res);
    // 打印兩次結果分別爲
    // 5, 1, ["1bb2", "b", "b"]
    // 10, 6, ["3dd4", "d", "d"]
}

字符串對象方法

String.prototype.search()

方法執行正則表達式和 String對象之間的一個搜索匹配,若是匹配成功,返回正則表達式在字符串中首次匹配項的索引,不然返回-1。

語法:

str.search(regexp)

若是傳入一個非正則表達式對象,則會使用 new RegExp(obj) 隱式地將其轉換爲正則表達式對象。

String.prototype.match()

用於搜索字符串,找到一個或多個與regexp匹配的文本
語法:

str.match(regexp);

返回值:

一個包含了整個匹配結果以及任何括號捕獲的匹配結果的 Array ;若是沒有匹配項,則返回 null。regexp是否有g標誌對返回值有很大影響。

非全局調用(不包含g標誌)

返回值和RegExp.prototype.exec()方法同樣,就不細說了。

全局調用(包含g標誌)

  1. 沒有找到任何匹配的字符串,返回null
  2. 若是找到了一個或多個匹配的字符串,則返回一個數組,存放字符串中全部匹配的字符串,不包含捕獲內容,也不具備index和input屬性。
var reg = /\d(\w)\d/g;
var str = '1a2b3c4d';
var res = str.match(reg);
console.log(res);  // ["1a2", "3c4"]
console.log(res.index);  // undefined
console.log(res.input);  // undefined

String.prototype.split()

split() 方法使用指定的分隔符字符串將一個String對象分割成字符串數組

語法:

str.split([separator[, limit]]);

separator 參數

當separator爲字符串時,其實也是默認轉成正則去執行

var str = 'a, b, c, d';
var arr = str.split(',');
var arr2 = str.split(/,/);
console.log(arr);  // ["a", " b", " c", " d"]
console.log(arr2);  // ["a", " b", " c", " d"]

separator帶捕獲括號

若是 separator 包含捕獲括號(capturing parentheses),則其匹配結果將會包含在返回的數組中。

var str = 'a1b2c3d';
var arr = str.split(/(\d)/);
console.log(arr); // ["a", "1", "b", "2", "c", "3", "d"]

limit參數

限制返回值中分割元素數量

var str = 'a b c d e';
var arr = str.split(' ', 3);
console.log(arr); //  ["a", "b", "c"]

String.prototype.replace()

replace() 方法返回一個由替換值替換一些或全部匹配的模式後的新字符串。模式能夠是一個字符串或者一個正則表達式, 替換值能夠是一個字符串或者一個每次匹配都要調用的函數。

注意: 原字符串不會改變。

語法:

str.replace(regexp|substr, newSubStr|function)

String.prototype.replace(substr, newSubStr)

var str = 'a1b2c3d';
var resStr = str.replace('1', 'X');
console.log(resStr); //

String.prototype.replace(regexp, newSubStr)

var str = 'a1b2c3d';
var resStr = str.replace(/\d/g, 'X');
console.log(resStr); //  aXbXcXd

String.prototype.replace(regexp, function)

function會在每次匹配替換的時候調用,包含四個可選參數

  1. 匹配到的字符串
  2. 正則表達式分組內容,沒有分組就沒有該參數
  3. 匹配項在字符串中的index
  4. 原字符串

例子:

好比要把'a1b2c3'替換後的結果爲'a2b3c4'

var str = 'a1b2c3';
var resStr = str.replace(/\d/g, function(matchStr, index, originStr) {
    // 此時正則表達式中無捕獲,function中則無分組參數
    return parseInt(matchStr) + 1;
});
console.log(resStr); // a2b3c4

當正則表達式中有捕獲時,再看一下另一個例子:

var str = 'a1b2c3d4e';
var resStr = str.replace(/(\d)(\w)(\d)/g, function(matchStr, group1, group2, group3, index, originStr) {
    // 會執行兩次回調,打印結果分別以下
    console.log(matchStr)  // 1b2   3d4
    console.log(group1);   // 1     3
    console.log(group2);   // b     d
    console.log(group3);   // 2     4
    return group1 + group3; //把匹配到的文本替換成group1 + group3字符串拼接後的值
});
// 把匹配到的1b2替換成group1 + group3(12), 3d4替換成(34)
console.log(resStr); // a12c34e  把匹配到的1b2替換成group1 + group3(12)

以上就是我總結的正則表達式相關知識, 感受把正則搞清楚仍是很爽滴, 如發現有問題請多多指教。

相關文章
相關標籤/搜索