正則表達式

正則表達式概述

正則表達式(regular expression)是一種表達文本模式(即字符串結構)的方法,有點像字符串的模板,常常用來按照“給定模式”匹配文本。比如,正則表達式給出一個 Email 地址的模式,然后用它來確定一個字符串是否為 Email 地址。

正則表達式的作用

  1. 給定的字符串是否符合正則表達式的過濾邏輯(匹配)
  2. 可以通過正則表達式,從字符串中獲取我們想要的特定部分(提取)
  3. 強大的字符串替換能力(替換)
正則表達式的特點
  1. 靈活性、邏輯性和功能性非常的強
  2. 可以迅速地用極簡單的方式達到字符串的復雜控制

創(chuàng)建一個正則表達式

1. 使用字面量以斜杠表示開始和結束

var regex = /xyz/;

2. 另一種是使用RegExp構造函數(shù)

var regex = new RegExp('xyz');

上面兩種寫法是等價的,都新建了一個內(nèi)容為xyz的正則表達式對象。它們的主要區(qū)別是,第一種方法在引擎編譯代碼時,就會新建正則表達式,第二種方法在運行時新建正則表達式,所以前者的效率較高。而且,前者比較便利和直觀,所以實際應用中,基本上都采用字面量定義正則表達式。

RegExp構造函數(shù)還可以接受第二個參數(shù),表示修飾符,如,

var regex = new RegExp('xyz', 'i');
// 等價于
var regex = /xyz/i;

修飾符

修飾符(modifier)表示模式的附加規(guī)則,放在正則模式的最尾部。
修飾符可以單個使用,也可以多個一起使用。

// 單個修飾符
var regex = /test/i;

// 多個修飾符
var regex = /test/ig;

g 修飾符

默認情況下,第一次匹配成功后,正則對象就停止向下匹配了。g修飾符表示全局匹配(global),加上它以后,正則對象將匹配全部符合條件的結果,主要用于搜索和替換。正則模式不含g修飾符,每次都是從字符串頭部開始匹配.正則模式含有g修飾符,每次都是從上一次匹配成功處,開始向后匹配

var regex = /b/g;
var str = 'abba';
regex.test(str); // true
regex.test(str); // true
regex.test(str); // false

i修飾符

正則對象區(qū)分字母的大小寫,加上i修飾符以后表示忽略大小寫(ignoreCase)加了i修飾符以后,不考慮大小寫。

m 修飾符

m修飾符表示多行模式(multiline),會修改和$的行為。默認情況下(即不加m修飾符時),^和$匹配字符串的開始處和結尾處,加上m修飾符以后,還會匹配行首和行尾,即^和會識別換行符(\n)。

/world$/.test('hello world\n') // false
/world$/m.test('hello world\n') // true

上面的代碼中,字符串結尾處有一個換行符。如果不加m修飾符,匹配不成功,因為字符串的結尾不是world;加上以后,$可以匹配行尾。

正則表達式實例方法

RegExp.prototype.test()

正則實例對象的test方法返回一個布爾值,表示當前模式是否能匹配參數(shù)字符串。

/cat/.test('cats and dogs') // true

如果正則表達式帶有g修飾符,則每一次test方法都從上一次結束的位置開始向后匹配

var r = /x/g;
var s = '_x_x';

r.lastIndex // 0
r.test(s) // true

r.lastIndex // 2
r.test(s) // true

r.lastIndex // 4
r.test(s) // false

上面代碼的正則表達式使用了g修飾符,表示是全局搜索,會有多個結果。接著,三次使用test方法,每一次開始搜索的位置都是上一次匹配的后一個位置。
注意,帶有g修飾符時,正則表達式內(nèi)部會記住上一次的lastIndex屬性,這時不應該更換所要匹配的字符串,否則會有一些難以察覺的錯誤。

var r = /bb/g;
r.test('bb') // true
r.test('-bb-') // false

RegExp.prototype.exec()

正則實例對象的exec()方法,用來返回匹配結果。如果發(fā)現(xiàn)匹配,就返回一個數(shù)組,成員是匹配成功的子字符串,否則返回null。

var s = '_x_x';
var r1 = /x/;
var r2 = /y/;
r1.exec(s) // ["x"]
r2.exec(s) // null

如果正則表達式包含圓括號(即含有“組匹配”),則返回的數(shù)組會包括多個成員。第一個成員是整個匹配成功的結果,后面的成員就是圓括號對應的匹配成功的組。也就是說,第二個成員對應第一個括號,第三個成員對應第二個括號,以此類推。整個數(shù)組的length屬性等于組匹配的數(shù)量再加1。
exec()方法的返回數(shù)組還包含以下兩個屬性:

  1. input:整個原字符串。
  2. index:模式匹配成功的開始位置(從0開始計數(shù))。
var r = /a(b+)a/;
var arr = r.exec('_abbba_aba_');
arr // ["abbba", "bbb"]
arr.index // 1
arr.input // "_abbba_aba_"

利用g修飾符允許多次匹配的特點,可以用一個循環(huán)完成全部匹配。

var reg = /a/g;
var str = 'abc_abc_abc'

while(true) {
  var match = reg.exec(str);
  if (!match) break;
  console.log('#' + match.index + ':' + match[0]);
}
// #0:a
// #4:a
// #8:a

上面代碼中,只要exec()方法不返回null,就會一直循環(huán)下去,每次輸出匹配的位置和匹配的文本。

正則實例對象的lastIndex屬性不僅可讀,還可寫。設置了g修飾符的時候,只要手動設置了lastIndex的值,就會從指定位置開始匹配。

字符串方法

String.prototype.match()

字符串實例對象的match方法對字符串進行正則匹配,返回匹配結果。默認情況下,match()方法只會找到第一個符合要求的內(nèi)容,找到以后就停止檢索。我們可以設置正則表達式為全局匹配模式,這樣就會匹配到所有的內(nèi)容,并以數(shù)組的形式返回。

var str = "1a2a3a4a5e6f7A8B9C";

    var result1 = str.match(/[a-z]/);   // 找到符合要求的第一個內(nèi)容,然后返回
    var result2 = str.match(/[a-z]/g);  // 設置為“全局匹配”模式,匹配字符串中 所有的小寫字母
    var result3 = str.match(/[a-z]/gi); // 設置多個匹配模式,匹配字符串中 所有的字母(忽略大小寫)

    console.log(result1); // 打印結果:["a"]
    console.log(result2); // 打印結果:["a", "a", "a", "a", "e", "f"]
    console.log(result3); // 打印結果:["a", "a", "a", "a", "e", "f", "A", "B", "C"]

String.prototype.search()

字符串對象的search方法,返回第一個滿足條件的匹配結果在整個字符串中的位置。如果沒有任何匹配,則返回-1。search()方法可以接受一個正則表達式作為參數(shù),然后會根據(jù)正則表達式去檢索字符串。serach()只會查找第一個,即使設置全局匹配也沒用。

var str = "hello abc hello aec afc";
    /*
    * 搜索字符串中是否含有abc 或 aec 或 afc
    */
    result = str.search(/a[bef]c/);
    console.log(result); // 打印結果:6

String.prototype.replace()

字符串對象的replace方法可以替換匹配的值。它接受兩個參數(shù),第一個是正則表達式,表示搜索模式,第二個是替換的內(nèi)容。

str.replace(被替換的內(nèi)容, 新的內(nèi)容)

參數(shù)解釋:

  1. 被替換的內(nèi)容:可以接受一個正則表達式作為參數(shù)。
  2. 新的內(nèi)容:默認只會替換第一個。如果需要替換全部符合條件的內(nèi)容,可以設置正則表達式為全局匹配模式。
 //replace()方法:替換
    var str2 = "Today is fine day,today is fine day !!!"

    console.log(str2);
    console.log(str2.replace("today","tomorrow"));  //只能替換第一個today
    console.log(str2.replace(/today/gi,"tomorrow")); //這里用到了正則,且為“全局匹配”模式,才能替換所有的today

String.prototype.split()

字符串對象的split方法按照正則規(guī)則分割字符串,返回一個由分割后的各個部分組成的數(shù)組。該方法接受兩個參數(shù),第一個參數(shù)是正則表達式,表示分隔規(guī)則,第二個參數(shù)是返回數(shù)組的最大成員數(shù)。

str.split(分隔符,返回數(shù)組的最大成員數(shù))
// 非正則分隔
'a,  b,c, d'.split(',')
// [ 'a', '  b', 'c', ' d' ]

// 正則分隔,去除多余的空格
'a,  b,c, d'.split(/, */)
// [ 'a', 'b', 'c', 'd' ]

// 指定返回數(shù)組的最大成員
'a,  b,c, d'.split(/, */, 2)
[ 'a', 'b' ]

正則表達式匹配規(guī)則

常用元字符串

元字符 說明
\d 匹配數(shù)字
\D 匹配任意非數(shù)字的字符
\w 匹配字母或數(shù)字或下劃線
\W 匹配任意不是字母,數(shù)字,下劃線
\s 匹配任意的空白符
\S 匹配任意不是空白符的字符
. 匹配除換行符以外的任意單個字符
^ 表示匹配行首的文本(以誰開始)
$ 表示匹配行尾的文本(以誰結束)

限定符

限定符 說明
* 重復零次或更多次
+ 重復一次或更多次
? 重復零次或一次
{n} 重復n次
{n,} 重復n次或更多次
{n,m} 重復n到m次

其他

  1. [] 字符串用中括號括起來,表示匹配其中的任一字符,相當于或的意思
  2. [^] 匹配除中括號以內(nèi)的內(nèi)容
  3. \ 轉(zhuǎn)義符
  4. | 或者,選擇兩者中的一個。注意|將左右兩邊分為兩部分,而不管左右兩邊有多長多亂
  5. () 從兩個直接量中選擇一個,分組

正則表達式貪婪匹配

默認情況下都是最大可能匹配,即匹配到下一個字符不滿足匹配規(guī)則為止。這被稱為貪婪模式。

var s = 'aaa';
s.match(/a+/) // ["aaa"]

上面代碼中,模式是/a+/,表示匹配1個a或多個a,那么到底會匹配幾個a呢?因為默認是貪婪模式,會一直匹配到字符a不出現(xiàn)為止,所以匹配結果是3個a。

除了貪婪模式,還有非貪婪模式,即最小可能匹配。只要一發(fā)現(xiàn)匹配,就返回結果,不要往下檢查。如果想將貪婪模式改為非貪婪模式,可以在量詞符后面加一個問號。

var s = 'aaa';
s.match(/a+?/) // ["a"]

上面例子中,模式結尾添加了一個問號/a+?/,這時就改為非貪婪模式,一旦條件滿足,就不再往下匹配,+?表示只要發(fā)現(xiàn)一個a,就不再往下匹配了。

除了非貪婪模式的加號(+?),還有非貪婪模式的星號(*?)和非貪婪模式的問號(??)。

  1. +?:表示某個模式出現(xiàn)1次或多2 次,匹配時采用非貪婪模式。
  2. *?:表示某個模式出現(xiàn)0次或多次,匹配時采用非貪婪模式。
  3. ??:表格某個模式出現(xiàn)0次或1次,匹配時采用非貪婪模式。

組匹配

正則表達式的括號表示分組匹配,括號中的模式可以用來匹配分組的內(nèi)容。

/fred+/.test('fredd') // true
/(fred)+/.test('fredfred') // true

分組捕獲

var m = 'abcabc'.match(/(.)b(.)/);
m
// ['abc', 'a', 'c']

上面代碼中,正則表達式/(.)b(.)/一共使用兩個括號,第一個括號捕獲a,第二個括號捕獲c。注意,使用組匹配時,不宜同時使用g修飾符,否則match方法不會捕獲分組的內(nèi)容。
括號還可以嵌套

/y((..)\2)\1/.test('yabababab') // true

上面代碼中,\1指向外層括號,\2指向內(nèi)層括號。

非捕獲組

(?:x)稱為非捕獲組(Non-capturing group),表示不返回該組匹配的內(nèi)容,即匹配的結果中不計入這個括號。

非捕獲組的作用請考慮這樣一個場景,假定需要匹配foo或者foofoo,正則表達式就應該寫成/(foo){1, 2}/,但是這樣會占用一個組匹配。這時,就可以使用非捕獲組,將正則表達式改為/(?:foo){1, 2}/,它的作用與前一個正則是一樣的,但是不會單獨輸出括號內(nèi)部的內(nèi)容。

var m = 'abc'.match(/(?:.)b(.)/);
m // ["abc", "c"]

先行斷言和先行否定斷言

  1. x(?=y)稱為先行斷言(Positive look-ahead),x只有在y前面才匹配,y不會被計入返回結果。比如,要匹配后面跟著百分號的數(shù)字,可以寫成/\d+(?=%)/。

  2. x(?!y)稱為先行否定斷言(Negative look-ahead),x只有不在y前面才匹配,y不會被計入返回結果。比如,要匹配后面跟的不是百分號的數(shù)字,就要寫成/\d+(?!%)/。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容