當(dāng)前位置:首頁>知識(shí)>正則表達(dá)式的一些基本用法(直接告訴你這些常用正則表達(dá)式是怎么寫出來的)
發(fā)布時(shí)間:2024-01-23閱讀(14)
作為一名程序員,不會(huì)寫正則表達(dá)式總感覺少了點(diǎn)什么,不要求你能把正則玩出花來,但最起碼要對(duì)常用的正則表達(dá)式手到擒來,剛畢業(yè)的我對(duì)于正則也是一頭霧水,不過學(xué)會(huì)它也就一篇教程的事情[1],下面我們就來說一說關(guān)于正則表達(dá)式的一些基本用法?我們一起去了解并探討一下這個(gè)問題吧!

正則表達(dá)式的一些基本用法
作為一名程序員,不會(huì)寫正則表達(dá)式總感覺少了點(diǎn)什么,不要求你能把正則玩出花來,但最起碼要對(duì)常用的正則表達(dá)式手到擒來,剛畢業(yè)的我對(duì)于正則也是一頭霧水,不過學(xué)會(huì)它也就一篇教程的事情[1]
本文我不會(huì)再浪費(fèi)帶寬把正則的規(guī)則再次重復(fù)一遍,而是從實(shí)際入手,直接告訴你為什么這么寫
16進(jìn)制顏色
按照規(guī)則來
第一句,可以寫成 /^#/;第二句,[a-fA-F0-9] 表示任意的 a-f、A-F、0-9,6或 3的個(gè)數(shù)可以用 {6}、{3}進(jìn)行表示,那么3個(gè)字符就是 [a-fA-F0-9]{3},6個(gè)字符就是 [a-fA-F0-9]{6},這兩個(gè)都有可能,用一個(gè)或(|)符號(hào)來連接:([a-fA-F0-9]{6}|[a-fA-F0-9]{3}),最后結(jié)尾可以用個(gè) $
所有合到一起就是 /^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/
鏈接
目標(biāo)是匹配出協(xié)議、域名、端口號(hào)port、path、search
合法的協(xié)議有 http、https,還有一個(gè)是自適應(yīng)協(xié)議,即不明確加協(xié)議,跟當(dāng)前頁面的協(xié)議保持一致,所以以下都是合法的:http://toutiao.com、https://toutiao.com、//toutiao.com。這三個(gè)協(xié)議組成的鏈接共同點(diǎn)是肯定有 // 字符串,在 //的前面可能是 https: 也可能是 http: 也可以沒有任何字符串 先按照 https:// 這種寫規(guī)則:^https://,其中的 s 字符可能有也可能沒有,所以使用 ? 修飾:^https?://,又因?yàn)?https?:可能沒有,所以這個(gè)字符串也用 ?修飾:^(https?:)?//
域名的前面可能是 //,從 //往后面匹配,只要沒有代表 :的 port、代表 search 的 ?、代表 path的 /,那么就都屬于域名:[^?:/]
端口號(hào)肯定以 : 開頭,后面跟著的只要是數(shù)字就都屬于 port::d ,由于不一定有端口號(hào),所以用 ? 修飾:(:d )?
肯定以 / 開頭,只要不遇到代表 search 的 ?,那么就都屬于 path:/[^?]*,由于可能沒有 path,所以用 ? 修飾:(/[^?]*)? 5. search 肯定以 ? 開頭,后面所有的字符都屬于 search(不考慮 hash 路由):?(.*),由于可能沒有 search,所以用 ? 修飾:(?.*)?
最后把上面所有規(guī)則合起來就是提取鏈接的完整正則了,考慮到需要精確提取所需要的部分,所以會(huì)對(duì)所需要提取的部分加上小括號(hào),結(jié)果為:/^((https?):)?//([^?:/] )(:(d ))?(/[^?]*)?(?(.*))?/
郵箱
以前在知乎上看到過一段郵箱正則,號(hào)稱是最符合標(biāo)準(zhǔn)的正則表達(dá)式,那條正則的體積好像有幾十KB吧,總之很長,現(xiàn)在找不到了,這里只關(guān)注常用的郵箱格式,規(guī)則:名稱允許漢字、字母、數(shù)字,下劃線,中劃線,域名可以有數(shù)字、字母、下劃線、中劃線組成
漢字的范圍是 [u4e00-u9fa5],字母的范圍是 [a-zA-Z],數(shù)字的范圍是 [0-9],合起來組成郵箱的名稱 ^[A-Za-z0-9-_u4e00-u9fa5]
域名是 [a-zA-Z0-9_-] ,域名后綴可以是多級(jí)域名 (.[a-zA-Z0-9_-] )
上面組合起來就是 ^[A-Za-z0-9-_u4e00-u9fa5] @[a-zA-Z0-9_-] (.[a-zA-Z0-9_-] ) $
手機(jī)號(hào)
手機(jī)號(hào)的號(hào)段可能是會(huì)增加的,所以在實(shí)際場(chǎng)景中不建議限制得太死了
本正則按照以下規(guī)則編寫:
上述三步合起來就是 /^1(3d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8d|9[0-35-9])d{8}$/
數(shù)字/貨幣金額
負(fù)號(hào)用 -負(fù)號(hào),且必須在第一位,即 ^-,再加個(gè) ? 用于表示這個(gè)負(fù)號(hào)可以有也可以沒有,即 ^-? 2. 支持千分位分隔(沒有也沒關(guān)系) 如果有千分位,則千分位的后面必然跟著三位數(shù)字(否則這個(gè)千分號(hào)就不應(yīng)該加了),千分位前面最少一位、最多三位數(shù)字,那么可以寫成 d{1,3},d{3},再精簡下,千分位前面的數(shù)字其實(shí)可以不用限制,因?yàn)橹灰^三位肯定就有千分位,就會(huì)被 d{3}捕獲,所以 d{1,3}換成 d 就行了,因?yàn)榉锨Х治坏目梢杂卸鄠€(gè)也可能沒有,所以寫成 d (,d{3})* 3. 如果有小數(shù),則小數(shù)點(diǎn)后最多兩位 小數(shù)點(diǎn)就是 .,后面跟著最多兩位數(shù)字 d{1,2},可能有小數(shù)也可能沒有,所以整體需要再加個(gè) ? 符號(hào),即 (.d{1,2})?
最終規(guī)則 /^-?d (,d{3})*(.d{1,2})?$/
身份證號(hào)
這里只看 2代身份證,18位數(shù)字 最后一位是校驗(yàn)位,可能為數(shù)字或字符X
最終規(guī)則 /^[1-9]d{5}(18|19|20)d{2}(0[1-9]|10|11|12)(0[1-9]|[1-2]d|30|31)d{3}[dX]$/
密碼校驗(yàn)
最少6位,包括至少1個(gè)大寫字母,1個(gè)小寫字母,1個(gè)數(shù)字,1個(gè)特殊字符
對(duì)于 至少1個(gè)大寫字母 這條規(guī)則,這個(gè)大寫字母的位置是不固定的,只要有就行,如果只有這一條規(guī)則的話,正則可以寫成 ^S*[A-Z] S*$,S 匹配任意非空白字符,這個(gè)規(guī)則即代表大寫字母的前面、后面可以跟著任意個(gè)(包括0個(gè))非空白字符
但除此之外還需要滿足最少1個(gè)小寫字母,1個(gè)數(shù)字,1個(gè)特殊字符,最少6位,你可以將這幾條規(guī)則都單獨(dú)寫出正則,然后目標(biāo)字符串跟這5條正則一一匹配,只要全部能匹配上就是對(duì)的,寫成 js 代碼就是:
functionmatch(s:string){return/^S*[A-Z] S*$/.test(s)&&/^S*[a-z] S*$/.test(s)&&/^S*[0-9] S*$/.test(s)&&/^S*[!@#$%^&*?] S*$/.test(s)&&/^S*S{6,}S*$/.test(s)}復(fù)制代碼如果就想在一條正則里實(shí)現(xiàn)這些校驗(yàn)?zāi)兀彩强梢缘模枰柚?零寬度正預(yù)測(cè)先行斷言 ((?=exp)),代表 匹配exp前面的位置
有了這個(gè)東西,就可以把上面5條規(guī)則寫到一起去了:/^S*(?=S{6,})(?=S*d)(?=S*[A-Z])(?=S*[a-z])(?=S*[!@#$%^&*?])S*$/
這條正則前面后面的 S* 還是之前的意思不變,中間是提取了5條規(guī)則的個(gè)性部分,然后通過 ?= 放在一起了,把規(guī)則里所有的 ?=去掉行不行?不行,因?yàn)槿绻サ舻脑挘紫染陀许樞蛏系臎_突了,例如上面的規(guī)則,如果把所有的 ?=去掉,就代表著 數(shù)字必須在大寫字母前面,大寫字母必須在小寫字母前面,特殊字母必須在小寫字母前面(除此之外整個(gè)正則也是有問題的)
你可以認(rèn)為 ?= 在匹配的時(shí)候會(huì)忽略掉其他的 ?=,只關(guān)心自己的前面能不能匹配成功,有多個(gè) ?=,則這多個(gè) ?= 都是只關(guān)心自己,忽略其他,但整條正則最后的結(jié)果是所有 ?= 匹配結(jié)果的并集,計(jì)算邏輯和上面的 js 是差不多的
提取 HTML 標(biāo)簽數(shù)據(jù)
要提取的標(biāo)簽字符串類似于 <div name="header">
只是正則話無法完成,需要借助 js
首先,把標(biāo)簽的屬性提取出來
這段標(biāo)簽包含標(biāo)簽開始符號(hào)、tag、屬性字符串、標(biāo)簽結(jié)束符號(hào)
開始符號(hào)是 <,標(biāo)簽名緊跟著開始符號(hào),且只要沒遇到空白符就都是標(biāo)簽名,所以連起來就是 <w s*
在開始符號(hào) 標(biāo)簽名,和 結(jié)束符號(hào)的中間,都是屬性,結(jié)束符號(hào)是 >,所以只要沒遇到結(jié)束符號(hào) >,就認(rèn)為是屬性字符串,用到了反向選擇 [^>]*s*>,合起來就是 /<w s*[^>]*s*>/,為了能捕獲屬性字符串,加個(gè)小括號(hào),即 /<w s*([^>]*)s*>/
conststr=`<divname="header">`constmt=str.match(/<w s*([^>]*)s*>/)//properties即屬性字符串,即name="header"constproperties=mt[1]復(fù)制代碼取到了 name="header" 之后,再對(duì)其進(jìn)行處理,觀察規(guī)律,每個(gè)屬性的鍵值對(duì)之間肯定存在空白符,不過卻不能通過空白符來直接分割,因?yàn)閷傩灾凳强梢源嬖诳瞻追模?
由于可能是自閉合標(biāo)簽,自閉合標(biāo)簽的最后有沒有 / 都是合法的,例如 <hr> 和 hr />都是合法的,所以需要兼容下:/<w s*([^>]*)s*/?>/
但屬性名是可以確定的,它可能是 = 左邊不包括空白符的內(nèi)容,再次用到反向選擇,從左往右匹配,反向選擇既不是=也不是不是空白符的內(nèi)容,即 [^s=]
雖然不確定屬性值是否包含空白符,但有個(gè)是確定的,即屬性值必然被引號(hào)包圍,所以直接取 = 右側(cè)所有引號(hào)的內(nèi)容即可,=".*?"
不過還有個(gè)問題,引號(hào)不僅可以是單引號(hào)還可以是雙引號(hào),即 =".*?" 和 =.*? 都行,如果第一個(gè)引號(hào)是雙引號(hào)開頭那么對(duì)應(yīng)的第二個(gè)引號(hào)也必然是雙引號(hào),反義單引號(hào)亦然,這里需要用到捕獲的規(guī)則了 =(["]).*?1,1的意思是這塊匹配的內(nèi)容跟第一捕獲組一樣,第一捕獲組也就是 ["],如果第一捕獲組匹配的是雙引號(hào),那么 1 就代表雙引號(hào),否則就代表單引號(hào)
至此整個(gè)正則為 [^s=] =(["]).*?1
不過還有個(gè)問題,屬性是可以沒有屬性值的,例如 <input type="checkbox" checked />,這里 checked 就是可以不寫屬性值的,所以再兼容下:/[^s=] (=(["]).*?2)?/,又因?yàn)橄M蹲綄傩院蛯傩灾担越o屬性和屬性值加個(gè)小括號(hào):/([^s=] )(=(["])(.*?)3)?/
上面的代表就可以繼續(xù)寫了
conststr=`<divname="header">`constmt=str.match(/<w s*([^>]*)s*>/)//properties即屬性字符串,即name="header"constproperties=mt[1]constmt1=properties.match(/([^s=] )(=(["])(.*?)3)?/g)constobj={}if(mt1){mt1.forEach(p=>{constkv=p.trim().split(=)obj[kv[0].trim()]=kv[1].trim().slice(1,-1)})}//obj=>{class:header-box,name:header}復(fù)制代碼小結(jié)
學(xué)會(huì)正則的最接途徑就是勤加練習(xí),平時(shí)遇到可以用正則解決的問題,就嘗試著正則解決,或許你一開始寫不出來,但可以去網(wǎng)上看看別人是怎么寫的,再自己獨(dú)立寫一遍,寫得多了自然就會(huì)了,沒什么訣竅,無非就是對(duì)正則規(guī)則的熟練掌握罷了
關(guān)于本文
來自:清夜https://juejin.cn/post/7073360739410378760
歡迎分享轉(zhuǎn)載→http://m.avcorse.com/read-104488.html
Copyright ? 2024 有趣生活 All Rights Reserve吉ICP備19000289號(hào)-5 TXT地圖HTML地圖XML地圖