js 的正則表達式平常用的不多,但以前抽取數據的時候用到過,主要是有這樣的需求;
var text='<td class="data">2014-4-4</td><br /><td class="data">2014-4-5</td>'; //希望輸出 ["2014-4-4", "2014-4-5"]
難倒不難,如何比較好的實現是個問題;
如果要提取其中的數據,主要就是 String 對象的 match()、replace()、split() 方法或者 RegExp 對象的 exec(),但是應用的時候,還是有點坑的;
首先寫出正則,這個不難,一個非全局,一個全局:
var re = /<td[^>]*?>([\s\S]*?)<\/td>/, reg = /<td[^>]*?>([\s\S]*?)<\/td>/g;
但是匹配多個 <td></td> 的時候,match 方法有點特殊:
match 的特殊在於:
非全局正則,可以返回捕獲組,也就是正則里面()里面的內容,但不能多次匹配;
全局正則,可以多次匹配,但不返回捕獲組;
實際上,如果全局正則,多次匹配還返回捕獲組的話,返回的數據就不可能是個簡單數組了,因為 n 次匹配,m 個捕獲組,那返回的結果就是,數組里有 n 個匹配結果,每個匹配結果里,還要放一個數組,用來表示每個捕獲組的值;
如果換成 exec(),結果如下:
exec() 特殊在於:
不管正則是否加全局,返回的內容是一樣的
具體實現:
1、這里,我們先用 match 實現一遍,按照前面的思路,就是用全局正則 match 一下,然后再遍歷獲取到的數組,通過非全局正則捕獲我們要的東西:
text.match(reg).map(function(v) { return v.match(re)[1]; }); //返回 ["2014-4-4", "2014-4-5"]
比較好理解,但是需要兩個正則,一個全局,一個非全局;
2、如果用 exec(),
var temp = [],data = []; while ((temp = reg.exec(text)) !== null) { data.push(temp[1]); } //data:["2014-4-4", "2014-4-5"]
這樣寫的原因是,RegExp 對象的方法,經常有 lastIndex 的屬性,exec() 在執行的時候,實際上每回只匹配一次,然后改了 lastIndex 屬性的值為下一個開始的地方,然后下次從新的地方開始再匹配,如果匹配到末尾匹配不到了,返回 null ,舉個例子:
這個特性不注意會被坑的,比如:
var reg=/ja/g,text='ja'; reg.test(text); //true reg.lastIndex 返回 2,其實也就是匹配到末尾了 reg.test(text); //false reg.lastIndex 返回 0,匹配到末尾沒匹配到,返回 null,lastIndex 重置為 0;
參考資料: