一段代碼引起的思考:正則表達式
var r = /\d/g; console.log(r.test('1')); console.log(r.test('1')); console.log(r.test('2')); console.log(r.test('2'));
先看看如上的代碼,不要執行,本身先猜想下結果。數組
正則在各個語言中,實現的標準並不徹底一致。咱們這裏就討論在 JavaScript
中的實現。測試
在 JavaScript
中,正則有四個修飾符: global, ignoreCase, multiline, unicode
,詳細請參考:MDN RegExp。prototype
它們的含義以下:code
i
i
比較易懂,在匹配的時候會忽略大小寫,示例以下:regexp
var text = 'abc'; var r = /abc/; console.log(r.test('abc')); // true console.log(r.test('Abc')); // false r = /abc/i; console.log(r.test('abc')); // true console.log(r.test('Abc')); // true
m
當匹配多行時,默認是全文本匹配,使用 m
以後,將對每一行進行單獨匹配。索引
// 定義一個多行文本 var text = `a b c A B C`; var r = /c$/; // 匹配以C結尾的文本 console.log(r.test(text)); // false 全文本匹配,匹配不上 r = /c$/m; console.log(r.test(text)); // true 多行匹配,c是第一行的末尾,匹配成功
u
使用修飾符 u
,將採用 Unicode
模式進行匹配,必需要在正則中包含unicode才能看到效果:ip
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個a,注意正則寫法 console.log(r.test('aaa')); // true
注意:在/u模式下,正則中 \u{xxx} 是一個總體,不可拆分。unicode
g
接下來,進入本文的重點,修飾符 g
的匹配模式。字符串
首先,咱們先回到開頭的那段代碼,我想大部分人的答案多是:true true true true
吧。
實際上,正確答案是:true false true false
,是否是以爲難以想象?接着往下看。
RegExp.prototype.test()
方法的邏輯是:當找到第一個匹配項時,返回 true
。查找整個字符串都沒有找到匹配項,返回 false
。
那具體又是如何查找的呢?這裏咱們就要看 RegExp
的另一個方法了:RegExp.prototype.exec()
。
注意觀察這個方法的返回值:
var r = /\d/; // 注意看,返回值是一個數組,除了匹配到的元素以外,還有一個 index 屬性 console.log(r.exec('123')); // ["1", index: 0, input: "123"]
關鍵就是 exec
返回值中的 index
屬性,這個屬性標識從輸入文本的哪個索引處開始查找匹配項。
若是不加 g
,每次都是從索引0處開始查找。
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
從結果咱們能夠看出,這個 index
是在變化的,當找不到匹配項時,會返回 null。
總結一下:修飾符 g
的做用,是標識是否須要全局存儲這個index。
有了這個理解,那麼回到以前的問題,那就說得通了。咱們使用了 g
修飾符,那麼會存儲上一次的 index
,當執行第二次 console.log(r.test('1'));
時,索引爲1,固然就匹配不上了,因此就返回了 false
。
那問題又來了,爲何第三次,又返回了 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')); // null console.log(r.exec('12')); // ["1", index: 0, input: "12"]
當發現已經匹配不上元素時,會將這個 index
從新設置爲 0
。
這也就解釋了最開始的整個代碼。