深入javascript中的exec與match方法
視頻課堂https://edu.csdn.net/course/play/7621
經典面試題,如果知曉一下題目的答案,那就沒有必要往下看了。
var someText="web2.0 .net2.0";
var pattern=/(\w+)(\d)\.(\d)/g;
var outCome_exec=pattern.exec(someText);
var outCome_matc=someText.match(pattern);
What is outCome_exec[1] and outCome_matc[1]?
Choice A: true
Choice B: false
Choice C: null
Choice D: Web
Choice E: Web2.0
Choice F: undefined
Choice G: net2.0
思考1分鐘ing........
在使用match方法時,如果不指定g屬性,則與RegExp對象的exec方法可以等價,而不是只有一個元素的數組。
舉例:
var str= "ahi" ;
var exp=/a(hi)/;
var arr1 = exp.exec(str);
var arr2 = str.match(exp);
alert(arr1);//結果:arr1.length==2;arr1[0]==ahi;arr1[1]==hi;
alert(arr2);//結果:arr2.length==2;arr2[0]==ahi;arr1[1]==hi;結果同上
3-2)同時,在js幫助文檔中,在執行exec方法時,如果有屬性g,將該對象的匹配的開始位置設置到緊接這匹配子串的字符位置,當第二次調用exec時,將從
lastIndex所指示的字符位置開始檢索。利用這個特點可以反復調用exec遍歷所有匹配,此時等價于match具有g屬性的情況(其實就是將匹配的結果放入Matches 集合中去了)。
舉例如下:
a)有屬性g的情況時,更新了index和lastIndex,對下次檢索起到作用:
function RegExpTest() {
var src = "The rain in Spain falls mainly in the plain.";
var re = /(\w+)/g; // 創建正則表達式模式。
var arr;
while ((arr = re.exec(src)) != null){
document.write(arr.index + "-" + RegExp.lastIndex + "\t" + arr[0]);//此處RegExp.lastIndex和arr.lastIndex均有同樣的屬性,可以互換。在此注意IE6和7的lastIndex重設置0的bug
}
};
RegExpTest();
//以上例子可以遍歷所匹配的內容。并可得到每個小匹配的index和lastIndex;
b)如果以上例子沒有g的情況,則以上例子,exec方法沒有更新RegExp?對象的全局屬性(index、lastIndex等),以上例子會陷入死循環,index和lastIndex一直為0和3
可見屬性g在exec過程中可以改變index和lastIndex等的值,以便下一次檢索的位置,match方法無此能力。
4.關于index和lastIndex等屬性(幫助中還有leftContext、rightContext、lastMatch、lastParen(最后一個括號),但是這些屬性均以index和lastindex為基礎)。
4-1)只讀屬性。
如下例子:
var src = "The rain in Spain falls mainly in the plain.";
var re = /(\w+)/g; // 創建正則表達式模式。
var arr;
arr = re.exec(src);
RegExp.lastIndex = 0;
RegExp.index = 0;
arr.lastIndex = 0;
arr.index = 0;
document.write(arr.index + "-" + arr.lastIndex + "\t" + arr[0]+"**********"+RegExp.index + "-" + RegExp.lastIndex + "\t" + arr[0]);
//結果為0-0 The**********0-3 The。
究其原因也就是RegExp的屬性是只讀的,即使js語言的靈活性,可以修任何屬性或添加任何屬性,均不報語法錯誤。但是依舊無法RegExp的屬性更改,但是arrary對象則是可以更改,但是每次執行一次exec,就會將RegExp.index等屬性重新賦值給返回的Arrary對象。
例如:
var src = "The rain in Spain falls mainly in the plain.";
var re = /(\w+)/g; // 創建正則表達式模式。
var arr;
arr = re.exec(src);
RegExp.lastIndex = 0;
RegExp.index = 0;
arr.lastIndex = 0;
arr.index = 0;
document.write(arr.index + "-" + arr.lastIndex + "\t" + arr[0]+"**********"+RegExp.index + "-" + RegExp.lastIndex + "\t" + arr[0]);
//執行第二次arr的index屬性會被更新,其實是RegExp對象實例在執行exec方法時,更新全局的RegExp.index和arr的index等,在后邊會介紹
arr = re.exec(src);
document.write("
"+arr.index + "-" + arr.lastIndex + "\t" + arr[0]+"**********"+RegExp.index + "-" + RegExp.lastIndex + "\t" + arr[0]);
//0-0 The**********0-3 The
//4-8 rain**********4-8 rain
4-2)不同的RegExp實例對象交叉執行exec時,index、lastIndex等屬性互不影響。每次執行exec或者執行String的match方法時,都會給RexExp.index等賦予新值。(這個其實是必須的,只是我在這腦袋一犯渾,給理解錯了,主要是因為“RegExp.lastIndex = 0;”可以被賦值,但是取值時,結果又沒有改變,讓我腦袋混亂了。)
開始我以為如果兩個RegExp對象在交叉執行exec時,可能index等會清零。因為我認為index屬性是保存在RegExp的全局靜態屬性上的。現在發現是保存在具體的RegExp實例上,每次執行exec或者執行String的match方法時,都會給RexExp.index等賦予新值。
呵呵,這可能是習慣了c和java中類和類實例的想法的人常犯的錯誤,認為RegExp是個類,RegExp.index是一個類的static屬性。這樣認為沒錯,但是他的值是是會在執行exec和String的match方法時,被正則對象更新。
舉例如下:
var src = "The rain in Spain falls mainly in the plain.";
var re1 = /(\w+)/; // 創建正則表達式模式。
var re2 = /(\w+)/g; // 創建正則表達式模式。
var arr;
arr = re1.exec(src);
document.write("R1第一次執行exec:"+RegExp.index + "-" + RegExp.lastIndex + "\t" + arr[0]);
arr = re2.exec(src);
document.write("
R2第一次執行exec:"+RegExp.index + "-" + RegExp.lastIndex + "\t" + arr[0]);
arr = re1.exec(src);
document.write("
R1第二次執行exec:"+RegExp.index + "-" + RegExp.lastIndex + "\t" + arr[0]);
arr = re2.exec(src);
document.write("
R2第二次執行exec:"+RegExp.index + "-" + RegExp.lastIndex + "\t" + arr[0]);
輸出的結果如下:
R1第一次執行exec:0-3 The
R2第一次執行exec:0-3 The
R1第二次執行exec:0-3 The
R2第二次執行exec:4-8 rain
4-3)String對象的match方法,無法像exec方法那樣獲取中間查找的對象的index和lastIndex,也就是說是一次性的。即無法得到下一次檢索的位置,match方法在設置g屬性時,只能獲取最后一個檢索和index和lastIndex;match在沒有設置g屬性時,僅僅獲得第一個匹配的index和lastIndex。
舉例如下:
a)
var src = "The rain in Spain falls mainly in the plain.";
var re = /\w+/g; //有g屬性。
var i = 0;
while (i++<10){
arr = src.match(re);
document.write(RegExp.index + "-" + RegExp.lastIndex + "\t" + arr + "
");
}
//結果如下:
38-43 The,rain,in,Spain,falls,mainly,in,the,plain
38-43 The,rain,in,Spain,falls,mainly,in,the,plain
38-43 The,rain,in,Spain,falls,mainly,in,the,plain
38-43 The,rain,in,Spain,falls,mainly,in,the,plain
38-43 The,rain,in,Spain,falls,mainly,in,the,plain
38-43 The,rain,in,Spain,falls,mainly,in,the,plain
38-43 The,rain,in,Spain,falls,mainly,in,the,plain
38-43 The,rain,in,Spain,falls,mainly,in,the,plain
38-43 The,rain,in,Spain,falls,mainly,in,the,plain
38-43 The,rain,in,Spain,falls,mainly,in,the,plain
b)
var src = "The rain in Spain falls mainly in the plain.";
var re = /\w+/; //?無g屬性。
var i = 0;
while (i++<10){
arr = src.match(re);
document.write(RegExp.index + "-" + RegExp.lastIndex + "\t" + arr + "
");
}
//結果如下:
0-3 The
0-3 The
0-3 The
0-3 The
0-3 The
0-3 The
0-3 The
0-3 The
0-3 The
0-3 The
c)
var src = "The rain in Spain falls mainly in the plain.";
var re = /\w+/g;
var i = 0;
arr = src.match(re);
while (arr[i]!=null){
document.write(RegExp.index + "-" + RegExp.lastIndex + "\t" + arr[i] + "
");
i++;
}
//結果如下:
38-43 The
38-43 rain
38-43 in
38-43 Spain
38-43 falls
38-43 mainly
38-43 in
38-43 the
38-43 plain
5.最后結論(如有不對,請指正):
1)exec是RegExp對象方法,match是String對象方法;
2)如果沒有找到結果,則二者都返回null;
3)只有在正則表達式必須指定全局g屬性時,match才能返回所有匹配,否則match與exec方法結果無差異,是等價的;
4)exec永遠返回與第一個匹配相關的信息,其返回數組第一個值是第一個匹配的字串,剩下的是所有分組的反向引用(即子括號的匹配內容);
5)exec在設置g屬性后,雖然匹配結果不受g的影響,返回結果仍然是一個數組(第一個值是第一個匹配到的字符串,以后的為分組匹配內容),但是會改變index和lastIndex等的值,將該對象的匹配的開始位置設置到緊接這匹配子串的字符位置,當第二次調用exec時,將從lastIndex所指示的字符位置開始檢索。同樣match方法在設置了g屬性后,也會改變index和lastIndex的值,但是是一次性的。無法像exec那樣能逐過程累積(即將結果放入Matches 集合中去了),因此無法累積獲取下一次檢索的位置。
PS:
最開始那個問題的答案為D和G。你想明白了么?
以上測試均在ie和firefox中測試過,結果一致。
以上測試的前提是javaScript支持RegExp對象。早期瀏覽器的javaScript引擎未必支持正則對象或者未必支持正則表達式對象的某些屬性。
JavaScript 正則表達式
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。