網站搜尋

為什麼 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。