深入瞭解javascript中的exec與match方法

來源:互聯網
上載者:User

 

這是我在csdn上的一篇文章,今天又忘記match的特性了,發現知識還得溫故而知新啊。

      

   一直以來對exec和match方法的區別有些混淆,今天重看協助文檔(協助文檔中主要依據一些晦澀的例子佐證,無助於理解),然後在百度搜集了下一些介紹文章,其中下面一篇文章(樓蘭之風...的《徹底領悟javascript中的exec與match方法》)被多次檢索,並在百度搜尋第一條。但是看完後,做了些例子,發現作者的結論有些問題,更正下,以避免誤導各位筒子們。

1.在看文章之前之前,引用下這個經典面試題,如果知曉一下題目的答案,那就沒有必要往下看了。

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........

 

 

 

 

 

 

            有些知識沒用過,思考兩天也沒用,所以思考不用太久。碰見這樣問題就直接google和百度吧!
2.思考未果完畢,現在看原文以及文中的結論:

作者原文如下:

 http://www.cnblogs.com/xiehuiqi220/archive/2008/11/05/1327487.html

 

最後作者總結的結論如下:

a)match是返回所有匹配的字串合成的數組,但是Regex必須指定全域g屬性才能返回所有匹配,不指定g屬性則會返回一個只有一個元素的數組。

b)exec永遠返回與第一個匹配相關的資訊,其返回數組包括第一個匹配的字串,所有分組的反向引用。

3.發現問題:

3-1)以上結論是錯誤的。在使用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; // 建立Regex模式。    
    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; // 建立Regex模式。   
    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; // 建立Regex模式。 
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("<br/>"+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+)/; // 建立Regex模式。 
    var re2 = /(\w+)/g; // 建立Regex模式。 
    var arr;

    arr = re1.exec(src);    
    document.write("R1第一次執行exec:"+RegExp.index + "-" + RegExp.lastIndex + "\t" + arr[0]);
    
    arr = re2.exec(src);
    document.write("<br/>R2第一次執行exec:"+RegExp.index + "-" + RegExp.lastIndex + "\t" + arr[0]);
    
    arr = re1.exec(src);
    document.write("<br/>R1第二次執行exec:"+RegExp.index + "-" + RegExp.lastIndex + "\t" + arr[0]);

    arr = re2.exec(src);
    document.write("<br/>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 + "<br/>");

}

//結果如下:

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 + "<br/>");

}
//結果如下:

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] + "<br/>");
    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)只有在Regex必須指定全域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引擎未必支援正則對象或者未必支援Regex對象的某些屬性。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.