常見的Regex表示式(更新RFC標準的email檢驗)

yeelan0319發表於2014-08-09

數字(Number)

除正常的數字(digit)之外,還有可能包括正、負號,科學計數法,小數位,甚至用逗號分隔千分位。

邏輯規則:

  • 起始位後一定是+/-號,也可以沒有 ^[+-]?
  • 至少有一位以上的數字 d+
  • 可能會跟著千分位分隔的逗號,暫時不考慮是否一定是3位分隔,規則可以出現一次或多次 (,d+)*
  • 如果是小數那麼一定是小數點後帶有至少一位以上的數字,規則僅能出現一次 (.d+)
  • 如果是科學計數法,則前面一定是小數,後面跟有e和次冪,規則僅能出現一次 (.d+(ed+))
  • 任何數字的結尾必須是數字

滿足上述條件檢驗數字的正規表示式為:^[+-]?d+(,d+)*(.d+(ed+)?)?$

符合該條件的example包括:

  • 3 (整數)
  • 3.14 (小數)
  • +3.14 (帶有+標識數字)
  • -2.5 (帶有-標識數字)
  • 128,234 (會計計數法)
  • 1.9e10 (科學計數法)

且過濾掉小數點重複出現多次,科學技術法不合規或重複出現多次,非數字如720p的字串
此處尤其要注意科學的條件,前面必須是合法小數後面是e和次冪,注意次冪必須有。


電話號碼(Phone Numbers)

美國的電話號碼規則:總計10位數字,但有可能帶有國家號碼1。可以接受的輸入格式包括:

  • xxx-xxx-xxxx
  • xxx xxx xxxx
  • (xxx)xxx-xxxx
  • xxxxxxxxxx
  • 1 上述格式組合
  • +1 上述格式組合

滿足上述條件檢驗美國電話的正規表示式為:^(+?1[s-])?(?d{3})?[s-]?d{3}[s-]?d{4}$

進一步可以將國家號的驗證修改為(+?d+[s-])?,這樣就可以支援諸如+86, 86 , 86-這樣的格式了。

中國的手機規則:總計11位數字,一般情況下不加上任何特殊符號的分隔。如果僅考慮以下4種格式:

  • xxxxxxxxxxx
  • +86-xxxxxxxxxxx
  • +86 xxxxxxxxxxx
  • +86xxxxxxxxxxx

滿足上述條件檢驗中國手機號碼的正規表示式為:^(+86[s-]?)?d{11}$


郵件(Email)

由於工作需要,更詳細的查閱了RFC對於郵件地址的標準要求。Google了很久居然始終沒有找到一份靠譜的中文翻譯。在此共享給大家,希望大家不用再去痛苦的翻那RFC晦澀的文件。

根據RFC 3696的規定,郵件地址(Email Address)被@符號分割為以下兩個組成部分:local name和domain name.

Local Name

  • 長度不超過64個字元
  • 可以由除@、反斜槓()、雙引號(“”)、逗號和方括號([ ])之外,任何ASCII Graphic字元組成。
  • 可以使用句號(.),但是不能出現在首尾的位置
  • 對於一些特殊情況,如老舊的系統、特殊目的的伺服器,可以使用全部ASCII字元(包括控制字元在內),但是必須使用反斜槓轉義單個字元,或者使用雙引號轉義整個字串。

Domain Name

  • 長度不超過255個字元
  • 只可以使用字母、數字和短橫線(-)
  • 可以使用短橫線(-),但是不能出現在首尾的位置
  • 其餘的要求包括頂級域名的白名單,每一級域名不可以超過64個字元、不可全部由數字組成等等

對於日常使用中,忽略Local Name第4點的要求1和Domain Name對域名合法性的過濾,可以使用如下正規表示式檢驗Email的合法性:

^[A-Za-z0-9!#$%&`+/=?^_`{|}~-]+(.[A-Za-z0-9!#$%&`+/=?^_`{|}~-]+)*@([A-Za-z0-9]+(?:-[A-Za-z0-9]+)?.)+[A-Za-z0-9]+(-[A-Za-z0-9]+)?$

如果使用Javascript的話,可以通過split函式,進一步檢驗每一部分的長度。

isemail: function(string){
    if(typeof string === "string"){
        var regex = /^[A-Za-z0-9!#$%&`*+/=?^_`{|}~-]+(?:.[A-Za-z0-9!#$%&`*+/=?^_`{|}~-]+)*@([A-Za-z0-9]+(?:-[A-Za-z0-9]+)?.)+[A-Za-z0-9]+(?:-[A-Za-z0-9]+)?$/;
        var temp = string.split("@");
        return regex.test(string) && temp[0].length <= 64 && temp[1].length <= 255;
     }
     else{
         return false;
     }
}

郵件的格式較為複雜,雖然實際上允許多級域名,只要長度保證在255個字元以內即可。不過更加常見的情況是,考慮@前面使用字元和.的情況,以及@後面可能會有二級域名的情況。如果不要求嚴格性而只是起到對於使用者的提示作用的話,滿足上述條件檢驗郵件的正規表示式為:^[w.]+(+[w.]+)?@w+(.w+){1,2}$

如果可能的話,理解了原理之後,還是更加推薦使用成熟的庫自帶的email檢驗函式,畢竟重複造輪子不是一件非常有效率的事情。


密碼(Password)

不同強度的密碼,
要求至少包含數字或字母:[da-zA-Z]d+[a-zA-Z]+[da-zA-Z]

必須數字、字母和特殊字元3種混排的:
(d+[a-zA-Z]+[-=\[];`,./~!@#$%^&*()_+|{}:"<>?]+) #數字開頭
|(d+[-
=[];`,./~!@#$%^&()_+|{}:”<>?]+[a-zA-Z]+) #數字開頭
|([a-zA-Z]+d+[-=\[];`,./~!@#$%^&*()_+|{}:"<>?]+) #字母開頭
|([a-zA-Z]+[-
=[];`,./~!@#$%^&
()+|{}:”<>?]+d+) #字母開頭
|([-=\[];`,./~!@#$%^&*()_+|{}:"<>?]+d+[a-zA-Z]+) #特殊字元開頭
|([-
=[];`,./~!@#$%^&*()
+|{}:”<>?]+[a-zA-Z]+d+) #特殊字元開頭


IP地址

IP地址是由4個使用句號(.)分割的數字序列組成,每段的數值取值在0-255之間。
由於數字會被當成字元看待,而沒有大小關係,使用正規表示式檢驗數字範圍是一件非常麻煩的事情。

檢驗IP地址的正規表示式如下:
(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9]).{3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])

使用Javascript,稍微優雅一點的表達方式

ip: function(string){
    var octet = `(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])`;
    var ip    = `(?:` + octet + `\.){3}` + octet;
    var ipRE  = new RegExp( `^` + ip + `$` );
    return ipRE.test(string);
}

HTML

HTML更為推薦使用其他的方式而非正規表示式進行過濾。
獲取Tag:<(w+)
獲取Tag內容:>([ws])<
獲取Attribute的值:=`([w://.]
)


更新記錄

2014年9月5日修改
原本的正規表示式中沒有考慮到yeelan0319@sf.com.32y8498這樣的內容也會被判定為true。還是對於正規表示式並非“全部字串匹配”,而是隻要出現“符合正規表示式規定的內容即可”的理解不夠透徹。說來說去最後好像還是推薦使用已經成熟的庫比較好,畢竟重複造輪子是一件太過於低效率的事情

2015年3月4日修改
根據RFC規定,更新了符合RFC詳細要求的email的正規表示式。
新增了IP地址的檢驗正則


  1. 雖然此處沒有考慮Local Name的第4點要求,但是RFC中其實規定,瀏覽器(Client Side)端檢驗不應該拒絕該格式的輸入,而應該交由郵件伺服器實際在執行過程中判斷其合法性,因為這樣的格式其實是完全合法的。此處其實是我偷懶了。 

相關文章