掌握正則表達(dá)式,是開發(fā)工程師的基本功,因此首先要掌握正則表達(dá)式的基本知識(shí)點(diǎn)!
一般程序員的姿勢(shì)
- 每次需要用正則表達(dá)式,就到網(wǎng)上copy一份,根本沒弄懂copy的正則表達(dá)式具體含義;
- 同一個(gè)項(xiàng)目中,多處用到同一種正則校驗(yàn),每次都是復(fù)制粘貼一份,萬一哪天領(lǐng)導(dǎo)說業(yè)務(wù)變動(dòng),正則表達(dá)式得調(diào)整,該起來相當(dāng)麻煩;
正則表達(dá)式正確的運(yùn)用姿勢(shì)
- 徹底理解正則表達(dá)式的基本原理/知識(shí)點(diǎn),即便是copy過來的正則表達(dá)式也得搞清楚為什么這么寫;
- 同一個(gè)項(xiàng)目當(dāng)中,同一種正則表達(dá)式,只能寫一遍,需要用到的地方直接引用,后期維護(hù)才能事半功倍!
今天來搞幾個(gè)郵箱正則表達(dá)式,匹配多級(jí)域名,包括中文域名

從上圖可以得出,除去“.”號(hào),域名既有英文(最多是6個(gè)字符),也有中文(最多是3個(gè)漢字)
而現(xiàn)在有很多影子郵箱/百變郵箱,是使用二級(jí)域名或者三級(jí)域名,所以,我們先列舉如下幾個(gè)郵箱,然后寫一個(gè)正則表達(dá)式,去匹配、判斷
mail_666@qq.com
mail_666@jack.uu.com
mail_666@jack.uu.com.cn
mail_666@qq.中文網(wǎng)
mail_666@jack.uu.中文網(wǎng)
mail_666@jack.uu.我愛你
思路
不管是什么郵箱,確定會(huì)有的字符是“@”和至少一個(gè)“.”(這里特指最后一個(gè)),那么我們就以這兩個(gè)確定的符號(hào)為分界點(diǎn),將每個(gè)郵箱拆分成3段,對(duì)每一段進(jìn)行正則匹配,最終組成整個(gè)郵箱的正則匹配。當(dāng)然進(jìn)入下一步之前,先理一理基本知識(shí)點(diǎn)。
正則表達(dá)式基本知識(shí)點(diǎn)
一、橫向模糊匹配(匹配字符串出現(xiàn)的長(zhǎng)度)
定義:一個(gè)正則可以匹配的字符串的長(zhǎng)度不是固定的,使用量詞可以達(dá)到這種目的。
量詞:比如{m , n} :表示連續(xù)出現(xiàn)最少 m 次,最多 n 次;跟在一個(gè)字符的后面就表示對(duì)該字符的限定。
比如郵箱的校驗(yàn):/^\w+@[a-z0-9]+.[a-z]{2,4}$/,寫在了[a-z]后面,表示可以有2到4位的字母
又比如手機(jī)號(hào)的校驗(yàn): /^1[3456789]\d{9}$/,跟在了\d后面,表示需要出現(xiàn)9個(gè)數(shù)字
對(duì)于量詞的總結(jié):
{m , n} :表示連續(xù)出現(xiàn)最少 m 次,最多 n 次
{m , } :表示至少出現(xiàn)m次
{m} :表示出現(xiàn)m次
? :等價(jià)于{0,1} 表示出現(xiàn)或不出現(xiàn)
+ :等價(jià)于{1,} 表示至少出現(xiàn)1次
* :等價(jià)于{0,} 表示出現(xiàn)任意次,可以不出現(xiàn)
二、縱向模糊匹配(匹配可能出現(xiàn)哪些字符)
定義:正則匹配的字符串對(duì)于某一位置上的字符來說,它可以有多種可能,不局限于某一類型,使用字符組可以達(dá)到這種目的。
字符組:比如[abc],表示該字符是可以字符 "a"、"b"、"c" 中的任何一個(gè)。對(duì)于這一位置來說,我們可以有3種可能性。
比如手機(jī)號(hào)的校驗(yàn): /^1[3456789]\d{9}$/,它在第二個(gè)位置,根據(jù)一般手機(jī)運(yùn)營(yíng)商來說,提供手機(jī)第二位的數(shù)字可以是3到9的任意一個(gè),才符合規(guī)范。
如果字符組里表示的字符特別多,可以使用范圍表示法,用連字符-來省略和縮寫。
比如郵箱的校驗(yàn):/^\w+@[a-z0-9]+.[a-z]{2,4}$/,它跟在@后面,根據(jù)我們郵箱的規(guī)范可知,@后面的[a-z0-9]+表示:數(shù)字0到9和字母a-z中的至少一個(gè)字符
三、常用的簡(jiǎn)寫形式
\d :表示[0-9],表示一位數(shù)字
\D :表示[^0-9],表示除數(shù)字外的任意字符
\w :表示[0-9a-zA-Z_],表示數(shù)字、大小寫字母和下劃線
\W :表示[^0-9a-zA-Z_],非單詞字符
\b :表示匹配一個(gè)單詞邊界,也就是指單詞和空格間的位置。例如,“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”
\B :匹配非單詞邊界?!癳r\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。
\s :匹配任何空白字符,包括空格、制表符、換頁符等等。等價(jià)于[ \f\n\r\t\v]。
\S :匹配任何非空白字符。等價(jià)于[^ \f\n\r\t\v]。
先上結(jié)論
js正則驗(yàn)證郵箱:/^\w+@[\da-z\.-]+\.([a-z]{2,6}|[\u2E80-\u9FFF]{2,3})$/
php正則驗(yàn)證郵箱:/^\w+@([\da-z\.-]+)\.([a-z]{2,6}|[\x7f-\xff]{6,9})/
這里簡(jiǎn)單解析一下:
- 第一段:@符號(hào)之前,其實(shí)就是郵箱的用戶名,現(xiàn)在一般郵箱的用戶名是字母、數(shù)字和下劃線組成的,用"\w",剛好
- 第二段:@符號(hào)之后最后一個(gè)“.”之前,“([\da-z.-]+)”,不管是js還是php,都是一樣的,匹配多個(gè)包含數(shù)字、小寫字母、“.”和“-”的字符串
- 第三段:最后一個(gè)“.”之后的部分:
對(duì)于js正則:([a-z]{2,6}|[\u2E80-\u9FFF]{2,3})
[a-z]{2,6}:匹配2~6個(gè)小寫字母
[\u2E80-\u9FFF]{2,3}:匹配2~3個(gè)中文漢字
js正則的中文漢字正則表達(dá)式來源于手冊(cè):https://tool.oschina.net/uploads/apidocs/jquery/regexp.html
對(duì)于php正則:([a-z]{2,6}|[\x7f-\xff]{6,9})
[a-z]{2,6}:匹配2~6個(gè)小寫字母
[\x7f-\xff]{6,9}:匹配2~3個(gè)中文漢字,在utf-8編碼中,3個(gè)字符為1個(gè)漢字
在utf-8編碼中,用ASCII碼表中的第128~255編碼中的3個(gè)編碼表示一個(gè)漢字,這里用十六進(jìn)制表示
驗(yàn)證一下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>正則表達(dá)式測(cè)試</title>
</head>
<body>
<script type="text/javascript" charset="utf-8">
//下面這個(gè)是匹配中文域名郵箱的
var patt1=new RegExp(/^\w+@([\da-z\.-]+)\.([a-z]{2,6}|[\u2E80-\u9FFF]{2,3})$/);
// var patt1=new RegExp(/^\w+@([\da-z\.-]+)\.([a-z]+|[\u2E80-\u9FFF]+)$/);
document.write(patt1.test("mail_666@qq.com")+" | ");
document.write(patt1.test("mail_666@jack.uu.com")+" | ");
document.write(patt1.test("mail_666@jack.uu.com.cn")+" | ");
document.write(patt1.test("mail_666@qq.中文網(wǎng)")+" | ");
document.write(patt1.test("mail_666@jack.uu.中文網(wǎng)")+" | ");
document.write(patt1.test("mail_666@jack.uu.我愛你")+" | ");
</script>
</body>
</html>
運(yùn)行結(jié)果:
true | true | true | true | true | true |
<?php
/**
* Create by PhpStorm
* User : Actor
* Date : 2021-06-25
* Time : 10:27
*/
//臨時(shí)啟用全局錯(cuò)誤提示
ini_set('display_errors', true);
error_reporting(E_ALL);
$rowBreak = (PHP_SAPI == 'cli') ? "\n" : '<br>';
$mailArr = [
'mail_666@qq.com',
'mail_666@jack.uu.com',
'mail_666@jack.uu.com.cn',
'mail_666@qq.中文網(wǎng)',
'mail_666@jack.uu.中文網(wǎng)',
'mail_666@jack.uu.我愛你',
];
$patternArr = [
'/^\w+@([\da-z\.-]+)\.([a-z]{2,6}|[\x7f-\xff]{6,9})/',
//'/^\w+@([\da-z\.-]+)\.([a-z\x7f-\xff]+)/',
//'/^\w+@([\da-z\.-]+)\.([a-z]{2,6}|[\x{4e00}-\x{9fa5}]{2,3})$/u',
//'/^\w+@([\da-z\.-]+)\.([a-z\x{4e00}-\x{9fa5}]+)$/u',
];
echo "<pre>";
foreach($patternArr as $pattern) {
foreach ($mailArr as $mail) {
echo "Pattern: {$pattern} {$rowBreak}";
var_dump(testRegExpMatch($pattern, $mail));
echo $rowBreak;
}
}
echo "</pre>";
/**
* 測(cè)試正則匹配
* @param string $pattern 正則表達(dá)式
* @param string $string 源字符串
* @return array
*/
function testRegExpMatch($pattern, $string) {
try {
preg_match($pattern, $string, $matches);
} catch (Exception $e) {
return array(
'stauts' => false,
'msg' => $e->getMessage(),
'matches' => array(),
);
}
return array(
'stauts' => true,
'msg' => 'Success',
'matches' => $matches,
);
}
運(yùn)行結(jié)果
Pattern: /^\w+@([\da-z\.-]+)\.([a-z]{2,6}|[\x7f-\xff]{6,9})/
array(3) {
["stauts"]=>
bool(true)
["msg"]=>
string(7) "Success"
["matches"]=>
array(3) {
[0]=>
string(15) "mail_666@qq.com"
[1]=>
string(2) "qq"
[2]=>
string(3) "com"
}
}
Pattern: /^\w+@([\da-z\.-]+)\.([a-z]{2,6}|[\x7f-\xff]{6,9})/
array(3) {
["stauts"]=>
bool(true)
["msg"]=>
string(7) "Success"
["matches"]=>
array(3) {
[0]=>
string(20) "mail_666@jack.uu.com"
[1]=>
string(7) "jack.uu"
[2]=>
string(3) "com"
}
}
Pattern: /^\w+@([\da-z\.-]+)\.([a-z]{2,6}|[\x7f-\xff]{6,9})/
array(3) {
["stauts"]=>
bool(true)
["msg"]=>
string(7) "Success"
["matches"]=>
array(3) {
[0]=>
string(23) "mail_666@jack.uu.com.cn"
[1]=>
string(11) "jack.uu.com"
[2]=>
string(2) "cn"
}
}
Pattern: /^\w+@([\da-z\.-]+)\.([a-z]{2,6}|[\x7f-\xff]{6,9})/
array(3) {
["stauts"]=>
bool(true)
["msg"]=>
string(7) "Success"
["matches"]=>
array(3) {
[0]=>
string(21) "mail_666@qq.中文網(wǎng)"
[1]=>
string(2) "qq"
[2]=>
string(9) "中文網(wǎng)"
}
}
Pattern: /^\w+@([\da-z\.-]+)\.([a-z]{2,6}|[\x7f-\xff]{6,9})/
array(3) {
["stauts"]=>
bool(true)
["msg"]=>
string(7) "Success"
["matches"]=>
array(3) {
[0]=>
string(26) "mail_666@jack.uu.中文網(wǎng)"
[1]=>
string(7) "jack.uu"
[2]=>
string(9) "中文網(wǎng)"
}
}
Pattern: /^\w+@([\da-z\.-]+)\.([a-z]{2,6}|[\x7f-\xff]{6,9})/
array(3) {
["stauts"]=>
bool(true)
["msg"]=>
string(7) "Success"
["matches"]=>
array(3) {
[0]=>
string(26) "mail_666@jack.uu.我愛你"
[1]=>
string(7) "jack.uu"
[2]=>
string(9) "我愛你"
}
}
全部通過
當(dāng)然,php正則匹配郵箱,還可以這樣子
/^\w+@([\da-z\.-]+)\.([a-z]{2,6}|[\x{4e00}-\x{9fa5}]{2,3})$/u
原理與/^\w+@([\da-z\.-]+)\.([a-z]{2,6}|[\x7f-\xff]{6,9})/類似。
最后,上面的幾個(gè)正則表達(dá)式是居于當(dāng)前市面上現(xiàn)存的域名進(jìn)行匹配的,下面提供幾個(gè)更加寬松的郵箱正則匹配
js正則匹配郵箱(寬松匹配):/^\w+@([\da-z\.-]+)\.([a-z]+|[\u2E80-\u9FFF]+)$/
php正則匹配郵箱(寬松匹配):/^\w+@([\da-z\.-]+)\.([a-z\x7f-\xff]+)/
php正則匹配郵箱(寬松匹配):/^\w+@([\da-z\.-]+)\.([a-z\x{4e00}-\x{9fa5}]+)$/u
原理都相似,可以對(duì)照理解下。如有誤,歡迎留言區(qū)批評(píng)指正。