2013-08-27 98 views
15

我正在定義一個正則表達式對象,然後在循環中匹配它。它只是偶爾匹配,確切地說 - 每隔兩次。所以我創建了這個問題的最小工作示例。爲什麼Javascript正則表達式每次都匹配一次?

我在Opera和Firefox中試過這段代碼。兩者的行爲相同:

>>> domainRegex = /(?:\.|^)([a-z0-9\-]+\.[a-z0-9\-]+)$/g; 
/(?:\.|^)([a-z0-9\-]+\.[a-z0-9\-]+)$/g 
>>> domainRegex.exec('mail-we0-f174.google.com'); 
Array [".google.com", "google.com"] 
>>> domainRegex.exec('mail-we0-f174.google.com'); 
null 
>>> domainRegex.exec('mail-we0-f174.google.com'); 
Array [".google.com", "google.com"] 
>>> domainRegex.exec('mail-we0-f174.google.com'); 
null 
>>> domainRegex.exec('mail-we0-f174.google.com'); 
Array [".google.com", "google.com"] 
>>> domainRegex.exec('mail-we0-f174.google.com'); 
null 

爲什麼會發生這種情況?此行爲是否記錄在案?除了在循環體內定義正則表達式之外,有沒有辦法解決這個問題?

+3

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec# Finding_successive_matches – Passerby

+1

[爲什麼使用Javascript中的全局標誌的RegExp會給出錯誤的結果?](http://stackoverflow.com/questions/1520800/why-regexp-with-global-flag-in-javascript-give-wrong-results ) – Bergi

+0

@GDR這是因爲[RegExp.lastIndex]發生的(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastIndex?redirectlocale=en-US&redirectslug=JavaScript %2FReference%2FGlobal_Objects%2FRegExp%2FlastIndex)(_ read「description」section_)。 –

回答

14

exec()以您描述的方式工作;本/g改性劑,它會返回一個比賽,從開始用lastIndex每次調用,直到有沒有更多的比賽,此時它返回nulllastIndex值重置爲0

但是,因爲你有

var domainRegex = /(?:\.|^)([a-z0-9\-]+\.[a-z0-9\-]+)$/; 
'mail-we0-f174.google.com'.match(domainRegex); // [".google.com", "google.com"] 
2

每次運行你的正則表達式的exec方法它可以讓你的下一場比賽時間:使用$不會有一個以上的比賽,所以你可以使用String.match()代替,失去了/g修改固定表達。

一旦到達字符串末尾,它會返回null,讓您知道您已獲得所有匹配項。下一次,它從開始再次開始。

由於您只有一個匹配(它會返回完整匹配數組和從括號中的匹配項),第一次,正則表達式將從頭開始搜索。它找到一個匹配並返回它。下一次,它會結束並返回null。所以,如果你有這樣一個循環中,你可以通過所有的比賽做這樣的事情循環:

while(regExpression.exec(string)){ 
    // do something 
} 

那麼下一次,它再次從位置0

開始「有怎麼辦?「

那麼,如果你知道只有一個匹配,或者你只想要第一個匹配,你可以將結果保存到一個變量。沒有必要重複使用.exec。如果你對所有比賽感興趣,那麼你需要繼續前進,直到你得到null

0

你爲什麼不使用簡單的搭配方法字符串如

'mail-we0-f174.google.com'.match(/(?:\.|^)([a-z0-9\-]+\.[a-z0-9\-]+)$/) 
+1

因爲它具有不良的表現,創建一個循環的每次迭代的正則表達式對象的新實例。 – GDR

+0

@GDR謝謝你解釋。 – dirtydexter

2

RegExp執行全局搜索時,exec方法開始於 的lastIndex property匹配開始。 lastIndex屬性在每個exec調用處設置,並且 被設置爲在找到的上次匹配之後的位置。如果匹配失敗,lastIndex被重置爲,這導致exec再次從頭開始匹配。

var a = 'asdfeeeasdfeedxasdf' 
undefined 
var p = /asdf/g 
p.lastIndex 
4 
p.exec(a) 
["asdf"] 
p.lastIndex 
11 
p.exec(a) 
["asdf"] 
p.lastIndex 
19 
p.exec(a) 
null //match failed 
p.lastIndex 
0 //lastIndex reset. next match will start at the beginning of the string a 

p.exec(a) 
["asdf"] 
0

附加信息來Ja͢cks響應:

您還可以設置lastIndex

var myRgx = /test/g; 
myRgx.exec(someString); 
myRgx.lastIndex = 0; 

或剛剛創建的每個執行,我覺得這更清潔的新的正則表達式

new RegExp(myRgx).exec(someString); 
相關問題