正則表達式有多強大一看便知!

  • 2021 年 5 月 16 日
  • 筆記

正則表達式並不難,只是很多人用得少所以記不住,但並不能否認它的強大之處!

正則表達式的作用

  1. 校驗字符串文本是否符合規則
  2. 提取符合規則的文本內容
  3. 替換文本內容

正則的字符含義

字符 描述
. 匹配除換行符外的任意字符,一個點只能匹配一個
\w 匹配字母數字下劃線或者漢字
\W 匹配任意不是字母,數字,下劃線,漢字的字符
\s 匹配空白字符,它和[ \t\n\r]等價(分別是空格製表符換行符回車符)
\S 匹配任意不是空白符的字符
\d 匹配數字(只能表示一位數字,可以替換為[0-9])
\D 匹配任意非數字的字符
\b 匹配單詞的開始或結束
\B 匹配不是單詞開頭或結束的位置
^ 匹配字符串的開始,在列舉的上面表示非,如[^\d]
a-Z 匹配a-Z之間的任意字符
$ 匹配字符串的結束
* 重複零次或多次
+ 重複一次或更多次
? 重複零次或一次
{n} 重複n次
{n,} 重複n次或更多次
{n,m} 重複n到m次
() 表示分組,就是括號裏面的作為一個整體
[] 表示字符串的列舉

相關方法

test()

  • 用於檢測字符串是否符合正則規定
let str = 'javascript'
let reg = /java/
// 檢測字符串是否包含'java'
console.log(reg.test(str)); //true

match()

  • match()可以檢索一個字符串或者一個正則的匹配,並將匹配到的結果通過數組返回,如果未加全局匹配,則只能通過數組返回匹配到的第一項結果,並會附加信息
var str="1 plus 2 equal 3"
console.log(str.match('equal')); //[ 'equal', index: 9, input: '1 plus 2 equal 3', groups: undefined ]
console.log(str.match(/\d+/)); //[ '1', index: 0, input: '1 plus 2 equal 3', groups: undefined ]
console.log(str.match(/\d+/g)); //[ '1', '2', '3' ]

replace()

  • replace() 方法用於在字符串中用一些字符替換另一些字符,或替換一個與正則表達式匹配的子串
  • stringObject.replace(regexp/substr,replacement)
    • 參數一為要替換的子字符串或要替換的模式的正則對象
    • 規定了替換文本或生成替換文本的函數
var str="Visit Microsoft!"
console.log(str.replace('Microsoft', "W3School")); //Visit W3School!
console.log(str.replace(/Microsoft/, "W3School")); //Visit W3School!

exec()

  • exec() 方法用於檢索字符串中的正則表達式的匹配
  • 通過exec()匹配到的每一項有效結果都會附加信息
  • 在都是非全局匹配的模式下,exec()返回的結果與match()相同;如果是全局匹配,exec()每被調用一次都會返回一項結果數組,直到無法匹配到內容時停下,返回null
let str="1 plus 2 equal 3"
let reg = /\d/g
console.log(reg.exec(str)); //[ '1', index: 0, input: '1 plus 2 equal 3', groups: undefined ]
console.log(reg.exec(str)); //[ '2', index: 7, input: '1 plus 2 equal 3', groups: undefined ]
console.log(reg.exec(str)); //[ '3', index: 15, input: '1 plus 2 equal 3', groups: undefined ]
console.log(reg.exec(str)); //null

應用實例

檢測手機號

  • 11位數

  • 第1位為1,第2位在(3,4,5,6,7,8,9)中選1位,3~11位為數字即可

function isPhoneNumber(tel) {
    var reg =/^1[3-9]\d{9}$/;
    return reg.test(tel);
}
isPhoneNumber('13997584510')

檢測郵箱

  • 以@為分隔符,在@之前以字母、數字開頭,之後還可以跟隨減號(-)或小數點(.),但不能同時跟隨
  • @之後必須緊跟字母或數字
  • 在此之後應緊跟至少一個特殊字符小數點(.)或減號(-),減號(-)可有可無,但是小數點(.)必須存在,並且以小數點後結尾,兩種特殊字符也可以共存。不管是小數點(.)還是減號(-),後面都要求跟字母或數字
function isEmail(str){
	var reg = /^[A-Za-z0-9]+[-\.]*@[A-Za-z0-9]+(-[A-Za-z0-9])*\.[A-Za-z0-9]+$/;
	return reg.test(str);
}
isEmail('[email protected]')

郵箱由於格式種類眾多,因此想用一個正則能夠檢測出所有的郵箱使不現實的,這使得郵箱的檢測必定不會完美

檢測密碼強度

  • 按照密碼強度標準,根據打分機制評定密碼強度

  • 長度(25分)

    • 5 分: 小於等於 4 個字符
    • 10 分: 5 到 7 字符
    • 25 分: 大於等於 8 個字符
  • 字母組成(25分)

    • 0 分: 沒有字母
    • 10 分: 包含字母但全都是小(大)寫字母
    • 25 分: 包含大小寫混合字母
  • 數字組成(20分)

    • 0 分: 沒有數字
    • 10 分: 1或2個數字
    • 20 分: 大於 2 個數字
  • 其它特殊符號(@#$%^&*)(25分)

    • 0 分: 沒有符號
    • 10 分: 1 個符號
    • 25 分: 大於 1 個符號
  • 額外獎勵(5分)

    • 2 分: 字母和數字
    • 3 分: 字母、數字和符號
    • 5 分: 大小寫字母、數字和符號
  • 最後評分標準:

    分數 等級
    >=90 非常安全
    >=80 安全
    >=70 非常強
    >=60
    >=50 一般
    >=25
    >=0 非常弱
  • 由於檢測規則較為複雜,因此借用了方法判斷

// 獲取總分數
function getTotalScore(password) {
    let totalScore = 0
    const regLowLetter = /[a-z]+/g
    const regUpLetter = /[A-Z]+/g
    const regAllLetter = /([a-z]+[A-Z]+)|([A-Z]+[a-z]+)/g
    const regSpecialChar = /[@#$%^&*]+/g
    const specialCharNum = password.match(regSpecialChar) ? password.match(regSpecialChar)[0].length : 0
    const regNumber = /\d*/g
    const numberLen = password.length - password.replace(regNumber, '').length
    const extral2 = /^(?=.*[a-zA-Z])(?=.*\d).*$/
    const extral3 = /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[@#$%^&*]).*$/
    const extral5 = /^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&*]).*$/

    // 檢測字符長度
    if (password.length >= 8) {
        totalScore += 25
    } else if (5 <= password.length) {
        totalScore += 10
    } else {
        totalScore += 5
    }
    // 檢測字母
    if (regAllLetter.test(password)) {
        totalScore += 25
    } else if (regLowLetter.test(password) || regUpLetter.test(password)) {
        totalScore += 10
    } else {
        totalScore += 0
    }
    // 檢測數字
    if (numberLen >= 3) {
        totalScore += 20
    } else if (0 < numberLen) {
        totalScore += 10
    } else {
        totalScore += 0
    }
    // 檢測其他字符
    if (specialCharNum == 1) {
        totalScore += 10
    } else if (specialCharNum > 1) {
        totalScore += 25
    } else {
        totalScore += 0
    }
    // 額外獎勵
    if (extral5.test(password)) {
        totalScore += 5
    } else if (extral3.test(password)) {
        totalScore += 3
    } else if (extral2.test(password)) {
        totalScore += 2
    } else {
        totalScore += 0
    }
    return totalScore
}
// 獲取級別
function getRank(password) {
    let totalScore = getTotalScore(password)
    switch (true) {
        case totalScore >= 90:
            console.log('密碼非常安全');
            break;
        case totalScore >= 80:
            console.log('密碼安全');
            break;
        case totalScore >= 70:
            console.log('密碼非常強');
            break;
        case totalScore >= 60:
            console.log('密碼強');
            break;
        case totalScore >= 50:
            console.log('密碼一般');
            break;
        case totalScore >= 25:
            console.log('密碼弱');
            break;
        case totalScore >= 0:
            console.log('密碼非常弱');
            break;
    }
}
getRank('ahhi1233217890#0')

替換文本

  • 以替換首尾空格為例,模擬trim()方法
function replaceText(text) {
    var reg = /^\s*|\s*$/;
    return text.replace(reg, '')
}
replaceText('                        Jfsd4324--_ ');

提取文本

  • 將windows後面跟着的版本號一起提取出來
let text = 'Windows 1.03 and Windows 2.0 fisrt Released in 1985 and 1987 respectively.Windows 95 and Windows 98 are the successor.Then Windows 2000 and Windows Xp appeared.Windows Vista is the Latest version of the family.'

function extractTetx(text) {
    let reg = /Windows ([\d.]|[a-zA-Z])+\b/g
    return text.match(reg)
}
console.log(extractTetx(text));

檢測身份證

  • 身份證的規則:

    • 15位:ai = xxxxxx yymmdd aa g
    • 18位:ai = xxxxxx yyyymmdd aa g p
    1. x 是6位是地區編碼,地區編碼首位不能為0

    2. ymd 分別表示年月日,表示出生日期,aa 是隨機碼,g是性別,p是校驗碼

  • 校驗碼計算規則:

    • 前17位號碼加權因子為 Wi = [ 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 ]

    • 驗證位 tt = [ 1, 0, 10, 9, 8, 7, 6, 5, 4, 3, 2 ]

    • 校驗碼 p = tt[i],其中 ,i是公式除11後取得的餘數,如2.31則 i=3,2.37 則 i =4

  • 由於檢測規則較為複雜,因此借用了方法判斷

// 判斷是否是身份證的核心方法
function isIDCard(str) {
    let getBirthday
    // 獲取身份證最後一位數,用於核對校驗碼
    let getLastNum = str.slice(-1, )
    if (str.length == 15) {
        getBirthday = str.slice(6, 12)
        // 出生日期核對(15位身份證無校驗碼)
        if (!(birthRule(getBirthday))) {
            return false
        }
    } else {
        getBirthday = str.slice(6, 14)
        // 校驗碼與生出日期核對
        if (!(birthRule(getBirthday) && countLastNum(str) == getLastNum)) {
            return false
        }
    }
    // 正則核對
    let reg = /(^[1-9]\d{13}(\d{3}[Xx]|\d{4})$)|(^[1-9]\d{11}(\d{3}[Xx]|\d{4})$)/;
    return reg.test(str);
}
// 判斷生日是否合法(string:birthday)
function birthRule(birthday) {
    let year = birthday.slice(0, -4)
    let month = birthday.slice(-4, -2)
    let day = birthday.slice(-2, )
    if (year.length === 2) {
        year = '19' + year
    }
    if (year > new Date().getFullYear() || month > 12) {
        return false
    }
    let days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    // 閏年
    if ((year % 100 !== 0 && year % 4 === 0) || year % 400 === 0) {
        days[1] = 29
    }
    if (day > days[month - 1]) {
        return false
    }
    return true
}
// 計算校驗碼(即使用上述公式)
function countLastNum(idCard) {
    let tt = [1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2]
    let wi = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
    let arr1 = []
    let totalNum = 0

    let arr2 = idCard.slice(0, 17).split('')
    arr2.forEach((item, i) => {
        arr1.push(parseInt(item) * wi[i])
    });
    totalNum = arr1.reduce((total, value) => total + value)
    return tt[mod(totalNum, 11)] - 1
}
// 取余函數
function mod(den, mol) {
    return parseInt((den / mol).toFixed(1).toString().split('.')[1])
}
console.log(isIDCard('422301196912307153'));

檢測QQ號

  • qq號的規則非常簡單:
    1. 5~11位數
    2. 首位不能為0
function isQQ(qq) {
    var reg = /^[1-9]\d{4,10}$/;
    return reg.test(qq);
}
console.log(isQQ('13997584510'));

檢測微信號

  • 必須以字母開頭,可以使用6-20位字母、數字、下劃線或減號(-)組合。
  • 不能設置中文
function isWeiXin(weiXin) {
    var reg = /^[a-zA-Z][a-zA-Z0-9_-]{5,19}$/;
    return reg.test(weiXin);
}
console.log(isWeiXin('J13997584510'));