0、前言

一段代碼引發(fā)的思考:

var r = /\d/g;console.log(r.test('1'));console.log(r.test('1'));console.log(r.test('2'));console.log(r.test('2'));

先看看如上的代碼,不要執(zhí)行,自己先猜測(cè)下結(jié)果。

1、正則修飾符

正則在各個(gè)語(yǔ)言中,實(shí)現(xiàn)的標(biāo)準(zhǔn)并不完全一致。我們這里就討論在 JavaScript 中的實(shí)現(xiàn)。

在 JavaScript 中,正則有四個(gè)修飾符: global, ignoreCase, multiline, unicode,詳細(xì)請(qǐng)參考:MDN RegExp。

它們的含義如下:

  • global(g) 針對(duì)字符串中所有可能的匹配來(lái)測(cè)試正則表達(dá)式

  • ignoreCase(i) 匹配時(shí)忽略大小寫(xiě)

  • multiline(m) 多行輸入將被視為多行(此時(shí)開(kāi)始^和結(jié)尾匹配$可以在每行中進(jìn)行匹配)

  • unicode(u) 對(duì)字符串采用unicode進(jìn)行匹配

修飾符:i

i 比較易懂,在匹配的時(shí)候會(huì)忽略大小寫(xiě),示例如下:

var text = 'abc';var r = /abc/;console.log(r.test('abc')); // trueconsole.log(r.test('Abc')); // falser = /abc/i;console.log(r.test('abc')); // trueconsole.log(r.test('Abc')); // true

修飾符:m

當(dāng)匹配多行時(shí),默認(rèn)是全文本匹配,使用 m 之后,將對(duì)每一行進(jìn)行單獨(dú)匹配。

// 定義一個(gè)多行文本var text = `a b cA B C`;var r = /c$/; // 匹配以C結(jié)尾的文本console.log(r.test(text)); // false 全文本匹配,匹配不上r = /c$/m;console.log(r.test(text)); // true 多行匹配,c是第一行的末尾,匹配成功

修飾符:u

使用修飾符 u,將采用 Unicode 模式進(jìn)行匹配,必須要在正則中包含unicode才能看到效果:

var r = /\u{61}/; // 匹配61次u字符console.log(r.test('a')); // false, 明顯匹配不上r = /\u{61}/u; // Unicode模式,\u{61} = 'a'console.log(r.test('a')); // true, Unicode下能匹配r = /\u{61}{3}/u; // 匹配3個(gè)a,注意正則寫(xiě)法console.log(r.test('aaa')); // true

注意:在/u模式下,正則中 \u{xxx} 是一個(gè)整體,不可拆分。

2、正則修飾符:g

接下來(lái),進(jìn)入本文的重點(diǎn),修飾符 g 的匹配模式。

首先,我們先回到開(kāi)頭的那段代碼,我想大部分人的答案可能是:true true true true 吧。

實(shí)際上,正確答案是:true false true false,是不是覺(jué)得不可思議?接著往下看。

RegExp.prototype.test()

RegExp.prototype.test() 方法的邏輯是:當(dāng)找到第一個(gè)匹配項(xiàng)時(shí),返回 true。查找整個(gè)字符串都沒(méi)有找到匹配項(xiàng),返回 false。

那具體又是如何查找的呢?這里我們就要看 RegExp 的另外一個(gè)方法了:RegExp.prototype.exec()。

注意觀(guān)察這個(gè)方法的返回值:

var r = /\d/;// 注意看,返回值是一個(gè)數(shù)組,除了匹配到的元素之外,還有一個(gè) index 屬性console.log(r.exec('123')); // ["1", index: 0, input: "123"]

關(guān)鍵就是 exec 返回值中的 index 屬性,這個(gè)屬性標(biāo)識(shí)從輸入文本的哪一個(gè)索引處開(kāi)始查找匹配項(xiàng)。

如果不加 g,每次都是從索引0處開(kāi)始查找。

var r = /\d/;console.log(r.exec('123')); // ["1", index: 0, input: "123"]console.log(r.exec('123')); // ["1", index: 0, input: "123"]console.log(r.exec('123')); // ["1", index: 0, input: "123"]

那如果加 g 呢?

var r = /\d/g;console.log(r.exec('123')); // ["1", index: 0, input: "123"]console.log(r.exec('123')); // ["2", index: 1, input: "123"]console.log(r.exec('123')); // ["3", index: 2, input: "123"]console.log(r.exec('123')); // null

從結(jié)果我們可以看出,這個(gè) index 是在變化的,當(dāng)找不到匹配項(xiàng)時(shí),會(huì)返回 null。

總結(jié)一下:修飾符 g 的作用,是標(biāo)識(shí)是否需要全局存儲(chǔ)這個(gè)index。

有了這個(gè)理解,那么回到之前的問(wèn)題,那就說(shuō)得通了。我們使用了 g 修飾符,那么會(huì)存儲(chǔ)上一次的 index,當(dāng)執(zhí)行第二次 console.log(r.test('1')); 時(shí),索引為1,當(dāng)然就匹配不上了,所以就返回了 false。

那問(wèn)題又來(lái)了,為什么第三次,又返回了 true 呢?

還是先看代碼:

var r = /\d/g;console.log(r.exec('12')); // ["1", index: 0, input: "12"]console.log(r.exec('12')); // ["2", index: 1, input: "12"]console.log(r.exec('12')); // nullconsole.log(r.exec('12')); // ["1", index: 0, input: "12"]

當(dāng)發(fā)現(xiàn)已經(jīng)匹配不上元素時(shí),會(huì)將這個(gè) index 重新設(shè)置為 0

http://www.cnblogs.com/humin/p/6927210.html