【原】無規矩,不方圓——說一說正則裏的exec()和test()

今天一大早遇就遇到一件詭異的事兒,多是思緒尚未澄靜下來,一會兒沒反應過來。事情是這樣的:正則表達式

模板:spa

<input class="name" type="text" placeholder="username">
<button type="submit">submit</button>

腳本:code

$("button").click(function(event) {
    event.preventDefault();
    var $name = $(".name").val();
    // 用戶名:以數字、字母或下劃線開頭,有6-20位
        var reg_name = /^[a-zA-Z0-9_]{1}[a-zA-Z0-9\*\._]{5,19}$/g;
        console.log(reg_name.test($name)); 
        if (reg_name.test($name)) {      
          console.log("correct!");
      } else {
          console.log("error!");        
      }
});

輸出:對象

true
error!

我在輸入框內填入「qqqqqq」,提交,我瞬間懵了,這這這,返回true了,你還給我走false分支?!此事必有蹊蹺。。。待我inner peace了一下以後,稍做調整,代碼正常了:blog

腳本:字符串

$("button").click(function(event) {
    event.preventDefault();
    var $name = $(".name").val();
    // 用戶名:以數字、字母或下劃線開頭,有6-20位
    var reg_name = /^[a-zA-Z0-9_]{1}[a-zA-Z0-9\*\._]{5,19}$/;
    console.log(reg_name.test($name));
    if (reg_name.test($name)) {
        console.log("correct!");
    } else {
        console.log("error!");
    }
});

輸出:get

true
correct!

我把正則表達式對象後邊的「g」修飾符給去掉以後,代碼可正常運轉。話說這個「g」的意思是:執行一個全局匹配,也即找到目標字符串中全部與表達式匹配的字符。而每一次執行exec(),只要一匹配到符合條件的字符,這個方法就立馬返回匹配的對象,它又是如何找到全部匹配的字符呢?這又牽扯到RegExp對象的lastIndex屬性,這個屬性返回的是與匹配的字符緊鄰的位置,也即第一個不與表達式匹配的字符的位置。這樣,咱們來個栗子:input

腳本:string

var str = "cat, fat, bat, pat";
var reg = /.al/g; 
var match = reg.exec(str);
console.log(match + ": " + match.index + "," + match[0] + "," + reg.lastIndex);
match = reg.exec(str); 
console.log(match + ": " + match.index + "," + match[0] + "," + reg.lastIndex);

輸出:it

cat: 0,cat,3
fat: 5,fat,8

上述代碼,咱們能夠看到,我對該字符串執行了兩次exec()方法,第一次,它匹配到了「cat」字符,lastIndex指的就是第一個「,」所在的位置,也即3,第二次,匹配到了「fat」字符,此時lastIndex指的就是第二個「,」所在的位置,也即8,lastIndex就像一個書籤,它記錄着每一次匹配進行的位置。咱們來換一個方式,看「g」修飾符如何盡情施展拳腳:

腳本:

var str = "cat, fat, bat, pat";
var reg = /.at/g;
while((matche = reg.exec(str)) != null) {
    console.log(matche + "," + matche.index + "," + matche[0] + "," + reg.lastIndex);
}

輸出:

cat,0,cat,3
fat,5,fat,8
bat,10,bat,13
pat,15,pat,18

喏,全部字符都如願以償的被匹配了,這就是「g」和「lastIndex」的強大之處。固然,我也知道了上述的詭異問題還有一個問題就是我對該字符串進行了兩次匹配,以前只知道test()方法返回布爾值,exec()方法返回匹配的結果,感受test()只是一把小刀,功能並無exec()強大,查了一下資料才發現並否則。

原話是這麼說的:「其實,調用test()和調用exec()是等價的,當exec()返回的結果不是null時,test()返回true,因爲這種等價性,當一個全局正則表達式調用test()方法時,它的行爲和exec()相同,由於它從lastIndex指定的位置開始檢索某個字符,若是找到了一個匹配結果,就馬上設置lastIndex的值爲當前匹配子串的結束位置,這樣一來,就可使用test()方法來遍歷字符串,就像使用exec()同樣。」(《權威指南》)

所以,咱們在寫正則的時候,必定要注意修飾符及方法的使用,若使用不當,勢必會對下次匹配形成不肯定的影響,同時也要記得,不要在正則表達式里加入空格,這一樣會對結果有影響。

最後再附幾個經常使用的正則:

// 用戶名:以數字、字母或下劃線開頭,有6-20位
var reg_name = /^[a-zA-Z0-9_]{1}[a-zA-Z0-9\*\._]{5 , 19}$/;
// 密碼:只能輸入6~20位的數字、字母、下劃線、*
var reg_pwd = /^[\w\*]{6,20}$/;
// 手機號:能夠以+或數字開頭,也能夠含有「—」和「 」
var reg_phone = /^[+]?(\d){3}[\s|-]?(\d){4}[\s|-]?(\d){4}$/;
//時間:年月日---   2016-01-20   16-02-02  20160202
var reg_time = /^\d{2}|\d{4}[-]?((0([1-9]{1}))|1[1|2])[-]?((0[1-9])|[1|2]\d)|(3|[0|1])$/;
// 郵箱:***@**.***

function isEmail (theStr) {
  var atIndex = theStr.indexOf('@');
  var dotIndex = theStr.indexOf('.', atIndex);
  var flag = true;
  theSub = theStr.substring(0, dotIndex+1)

  if ((atIndex < 1)||(atIndex != theStr.lastIndexOf('@'))||(dotIndex < atIndex + 2)||(theStr.length <= theSub.length)) {

    return(false);

  }else {

    return(true);

  }}

相關文章
相關標籤/搜索