問(wèn)題背景
最近幫同事解決了一個(gè)正則問(wèn)題言沐,挺有意思邓嘹,分享給大家
背景是同事在做一個(gè)用戶注冊(cè)相關(guān)的功能,甲方提出了一些對(duì)密碼復(fù)雜度的要求险胰,要求長(zhǎng)度8-32位汹押,小寫(xiě)字母,大寫(xiě)字母起便,數(shù)字棚贾,符號(hào)四種必須都有,下面是匹配密碼的最初的正則表達(dá)式
(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z])(?=.*[^a-zA-Z0-9]).{8,32}
問(wèn)題驗(yàn)證
大家可以看一下這個(gè)正則榆综,感覺(jué)一下用這個(gè)正則能夠滿足上面的密碼校驗(yàn)要求嗎妙痹?可以花一點(diǎn)時(shí)間想一想
答案是:不能
我們來(lái)做個(gè)簡(jiǎn)單的測(cè)試,建議找一個(gè)在線工具鼻疮,實(shí)際測(cè)試一下
把表達(dá)式輸入進(jìn)去怯伊,我們測(cè)如下幾段文本
- abc123A:沒(méi)有匹配,長(zhǎng)度不夠
- abcd12345:沒(méi)有匹配陋守,復(fù)雜度不夠震贵,沒(méi)有大寫(xiě)和符號(hào)
- abcdA123-:能夠正常匹配利赋,長(zhǎng)度符合,復(fù)雜度符合
那這不是說(shuō)明這個(gè)正則是OK的嗎猩系?我們?cè)贉y(cè)下面這個(gè)文本
- abcdA123-我:這怎么也匹配了
- abc他dA★123:這怎么也匹配了
問(wèn)題改進(jìn)
這個(gè)正則里面有兩個(gè)小問(wèn)題
- 符號(hào)限定過(guò)于寬泛:(?=.*[^a-zA-Z0-9])這個(gè)判非就把其他所有字符都囊括進(jìn)來(lái)了
- 沒(méi)有輸入文本的限定:.{8,32}這個(gè)點(diǎn)也囊括了除換行以外的所有字符
針對(duì)上面兩個(gè)問(wèn)題改進(jìn)一下這個(gè)正則媚送,首先要枚舉我們?cè)试S出現(xiàn)的符號(hào),假設(shè)我們只允許出現(xiàn) “-_” 這兩個(gè)字符
改進(jìn)后的正則如下
^(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z])(?=.*[-_])[0-9a-zA-Z-_]{8,32}$
這個(gè)問(wèn)題一方面是缺乏測(cè)試驗(yàn)證寇甸,但更深層的原因其實(shí)是對(duì)正則不夠了解塘偎,不能快速發(fā)現(xiàn)正則的問(wèn)題,下一節(jié)我們就來(lái)看看這個(gè)正則里面比較困難的部分
擴(kuò)展閱讀
可能有同學(xué)有疑問(wèn)前面這么一大堆括號(hào)是干什么的
這里復(fù)習(xí)一下正則表達(dá)式的一個(gè)基礎(chǔ)概念:零寬斷言
零寬斷言是一種零寬度的匹配,它匹配到的內(nèi)容不會(huì)保存到匹配結(jié)果中去,最終匹配結(jié)果只是一個(gè)位置而已拿霉。
(?=)就是一種零寬斷言吟秩,叫做正向先行斷言,主要作用是匹配表達(dá)式后面的內(nèi)容
比如:\d(?=px)绽淘,這個(gè)正則能匹配到1px中的1涵防,不會(huì)匹配到2pm中的2,因?yàn)?后面跟的不是px沪铭,如果想同時(shí)把px也匹配上壮池,那就得寫(xiě)\d(?=px)px,這看起來(lái)就跟\dpx一樣了杀怠,在匹配單個(gè)條件的時(shí)候的確沒(méi)有區(qū)別椰憋,但匹配多條件的時(shí)候就不一樣了
我們還是用例子來(lái)解釋一下
[a-z0-9]{4,10}
這樣一個(gè)正則能表示英文小寫(xiě)和數(shù)字出現(xiàn)4-10次,但不能要求必須同時(shí)有英文和數(shù)字赔退,可以是純英文橙依,也可以是純數(shù)字
正則是一種順序性的描述性語(yǔ)言,1a和a1是不同的硕旗,如果想描述這種不確定位置的組合窗骑,對(duì)于普通正則寫(xiě)法來(lái)說(shuō)是比較困難的,基本就變成了排列組合了
這時(shí)我們就可以通過(guò)正向先行斷言來(lái)幫助進(jìn)行匹配卵渴,正向先行斷言可以理解成對(duì)字符串的模式匹配
(?=.*[a-z])
表示后面必須出現(xiàn)一個(gè)英文小寫(xiě)慧域,但是位置可以不定,使用.*來(lái)表達(dá)位置不定這個(gè)信息
同理
(?=.*[0-9])
表示后面必須出現(xiàn)一個(gè)數(shù)字浪读,但是位置可以不定
[a-z0-9]{4,10}限定輸入內(nèi)容和長(zhǎng)度
(?=.*[a-z])(?=.*[0-9])[a-z0-9]{4,10}
連接在一起就能表示英文小寫(xiě)和數(shù)字出現(xiàn)4-10次昔榴,且英文和數(shù)字都必須至少出現(xiàn)一次