為什麼 Javascript 的 regex.exec() 並不總是返回相同的值?
在 Chrome 或 Firebug 控制台中:
reg = /ab/g
str = "abc"
reg.exec(str)
==> ["ab"]
reg.exec(str)
==> null
reg.exec(str)
==> ["ab"]
reg.exec(str)
==> null
exec 是否以某種方式有狀態,並依賴於它上一次返回的結果?還是這只是個錯誤?我無法讓它每次都發生。例如,如果上面的 'str' 是 "abc abc",就不會發生。
答案#1
JavaScript 的 RegExp 物件是有狀態的。
當正則表達式是全域的,如果你在同一個正則表達式對象上呼叫方法,它將從上一次匹配結束之後的索引開始。
當找不到更多匹配時,索引會自動重置為 0。
要手動重設它,請設定 lastIndex 屬性。
reg.lastIndex = 0;
這可以是一個非常有用的功能。如果需要,你可以在字串的任何位置開始評估,或者如果在循環中,你可以在達到期望的匹配數後停止它。
這裡展示了一個在循環中使用正則表達式的典型方法。它利用了這樣一個事實:當沒有更多匹配時,exec 會返回 null,並通過將賦值作為循環條件來實現。
var re = /foo_(\d+)/g,
str = "text foo_123 more text foo_456 foo_789 end text",
match,
results = [];
while (match = re.exec(str))
results.push(+match[1]);
示範: http://jsfiddle.net/pPW8Y/
如果你不喜歡作業的擺放位置,迴圈可以重新設計,例如像這樣...
var re = /foo_(\d+)/g,
str = "text foo_123 more text foo_456 foo_789 end text",
match,
results = [];
do {
match = re.exec(str);
if (match)
results.push(+match[1]);
} while (match);
示範: http://jsfiddle.net/pPW8Y/1/
答案#2
來自 MDN 文件:
如果你的正則表達式使用了「g」標誌,你可以多次使用 exec 方法來在同一個字串中尋找連續的匹配。當你這樣做時,搜尋會從字串中由正則表達式的 lastIndex 屬性指定的子字串開始(test 也會推進 lastIndex 屬性)。
由於你正在使用 g 標誌,exec 會從最後匹配的字串繼續,直到結束(返回 null),然後重新開始。
就我個人而言,我更喜歡用 str.match(reg) 反過來做
答案#3
多個匹配
如果你的正則表達式需要 g 標誌(全局匹配),你將需要使用 lastIndex 屬性來重置索引(上一次匹配的位置)。
reg.lastIndex=0;
這是因為 exec() 會在每次出現時停止,因此你可以在剩餘部分上再次運行。這種行為在 test() 中也存在) :
如果你的正則表達式使用了 "g" 標誌,你可以多次使用 exec 方法來在同一個字串中找到連續的匹配。當你這麼做時,搜尋將從 str 的子字串開始,這個子字串由正則表達式的 lastIndex 屬性指定(test 也會推進 lastIndex 屬性)。
單場比賽
當只有一個可能的匹配時,你可以簡單地通過省略g標誌來重寫你的正則表達式,因為索引將自動重置為0。
