<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          別再說概念了!直接告訴我這些常用正則表達(dá)式是怎么寫出來的行不行?

          共 5443字,需瀏覽 11分鐘

           ·

          2022-04-30 13:08

          作為一名程序員,不會(huì)寫正則表達(dá)式總感覺少了點(diǎn)什么,不要求你能把正則玩出花來,但最起碼要對常用的正則表達(dá)式手到擒來,剛畢業(yè)的我對于正則也是一頭霧水,不過學(xué)會(huì)它也就一篇教程的事情[1]

          本文我不會(huì)再浪費(fèi)帶寬把正則的規(guī)則再次重復(fù)一遍,而是從實(shí)際入手,直接告訴你為什么這么寫

          16進(jìn)制顏色

          按照規(guī)則來

          1. # 開頭
          2. 后面緊跟著6個(gè)字符或者3個(gè)字符作為結(jié)尾,這些字符可以是 a-f 的小寫字母、A-F的大寫字母、數(shù)字

          第一句,可以寫成 /^#/;第二句,[a-fA-F0-9] 表示任意的 a-f、A-F、0-9,63的個(gè)數(shù)可以用 {6}{3}進(jìn)行表示,那么3個(gè)字符就是 [a-fA-F0-9]{3},6個(gè)字符就是 [a-fA-F0-9]{6},這兩個(gè)都有可能,用一個(gè)或(|)符號來連接:([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é)議、域名、端口號port、path、search

          1. 協(xié)議

          合法的協(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?:)?\/\/

          1. 域名

          域名的前面可能是 //,從 //往后面匹配,只要沒有代表 :port、代表 search?、代表 path/,那么就都屬于域名:[^?:/]+

          1. 端口號 port

          端口號肯定以 : 開頭,后面跟著的只要是數(shù)字就都屬于 port:\d+,由于不一定有端口號,所以用 ? 修飾:(:\d+)?

          1. path

          肯定以 / 開頭,只要不遇到代表 search?,那么就都屬于 path\/[^?]*,由于可能沒有 path,所以用 ? 修飾:(\/[^?]*)? 5. search 肯定以 ? 開頭,后面所有的字符都屬于 search(不考慮 hash 路由):\?(.*),由于可能沒有 search,所以用 ? 修飾:(\?.*)?

          最后把上面所有規(guī)則合起來就是提取鏈接的完整正則了,考慮到需要精確提取所需要的部分,所以會(huì)對所需要提取的部分加上小括號,結(jié)果為:/^((https?):)?\/\/([^?:/]+)(:(\d+))?(\/[^?]*)?(\?(.*))?/

          郵箱

          以前在知乎上看到過一段郵箱正則,號稱是最符合標(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_-]+,域名后綴可以是多級域名 (\.[a-zA-Z0-9_-]+)+

          上面組合起來就是 ^[A-Za-z0-9-_\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$

          手機(jī)號

          手機(jī)號的號段可能是會(huì)增加的,所以在實(shí)際場景中不建議限制得太死了

          本正則按照以下規(guī)則編寫:

          1. 11位數(shù)字,以數(shù)字 1 開頭,即 ^1
          2. 接下來的數(shù)字如果是 3,那么 3后面可以跟一個(gè)任意數(shù)字,即 3\d;如果是 4,那么 4后面可以跟一個(gè)5-9之間的數(shù)字,即 4[5-9];如果是 5,那么 5后面可以跟一個(gè)0-35-9之間的數(shù)字,即 5[0-35-9];如果是 6,那么 6后面可以跟 2、5、67 其中一個(gè)數(shù)字,即 6[2567];如果是 7,那么 7后面可以跟一個(gè)0-8之間的數(shù)字,即 7[0-8];如果是 8,那么 8后面可以跟一個(gè)任意數(shù)字,即 8\d;如果是 9,那么 9后面可以跟一個(gè)0-35-9之間的數(shù)字,即 9[0-35-9]
          3. 最后 8位可以是任意數(shù)字

          上述三步合起來就是 /^1(3\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\d|9[0-35-9])\d{8}$/

          數(shù)字/貨幣金額

          1. 支持負(fù)數(shù)

          負(fù)號用 -負(fù)號,且必須在第一位,即 ^-,再加個(gè) ? 用于表示這個(gè)負(fù)號可以有也可以沒有,即 ^-? 2. 支持千分位分隔(沒有也沒關(guān)系) 如果有千分位,則千分位的后面必然跟著三位數(shù)字(否則這個(gè)千分號就不應(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è) ? 符號,即 (\.\d{1,2})?

          最終規(guī)則 /^-?\d+(,\d{3})*(\.\d{1,2})?$/

          身份證號

          這里只看 2代身份證,18位數(shù)字 最后一位是校驗(yàn)位,可能為數(shù)字或字符X

          1. 第一位數(shù)字在 [1-9] 閉區(qū)間內(nèi),后面緊跟著5位任意數(shù)字,寫成 ^[1-9]\d{5}

          2. 再緊跟著的四位數(shù)字代表年份(YYYY),因?yàn)槟壳坝猩矸葑C的人最早是19世紀(jì)最晚21世紀(jì),所以這四個(gè)數(shù)字中的前兩位只看是 1819、20,即 (18|19|20),后兩位則可以是任意數(shù)字,即 \d{2}

          3. 再緊跟著兩位數(shù)字是月(MM),月份只可能是 [1-12]閉區(qū)間,所以可以寫成 (01|02|03|04|05|06|07|08|09|10|11|12),前九位的開頭都是 0,第二位是 [1-9] 內(nèi)的數(shù)字,所以簡化成 (0[1-9]|10|11|12)

          4. 再緊跟著兩位數(shù)字是日(DD),范圍是 [01-31],可以將這31個(gè)數(shù)字羅列出來,當(dāng)然也可以精簡下,看成是 [00-09][10-29]、[30-31]的組合,即 (0[1-9]|[1-2]\d|30|31)

          5. 再緊跟著三位數(shù)字是順序碼,即 \d{3}

          6. 最后一位是校驗(yàn)碼,可以是數(shù)字也可以是 X,即 [\dX]

          最終規(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è)特殊字符

          對于 至少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條正則一一匹配,只要全部能匹配上就是對的,寫成 js 代碼就是:

          function?match(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ù)測先行斷言(?=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)簽字符串類似于

          只是正則話無法完成,需要借助 js

          首先,把標(biāo)簽的屬性提取出來

          這段標(biāo)簽包含標(biāo)簽開始符號、tag、屬性字符串、標(biāo)簽結(jié)束符號

          開始符號是 <,標(biāo)簽名緊跟著開始符號,且只要沒遇到空白符就都是標(biāo)簽名,所以連起來就是 <\w+\s*

          在開始符號+標(biāo)簽名,和 結(jié)束符號的中間,都是屬性,結(jié)束符號是 >,所以只要沒遇到結(jié)束符號 >,就認(rèn)為是屬性字符串,用到了反向選擇 [^>]*\s*>,合起來就是 /<\w+\s*[^>]*\s*>/,為了能捕獲屬性字符串,加個(gè)小括號,即 /<\w+\s*([^>]*)\s*>/

          const?str?=?``
          const?mt?=?str.match(/<\w+\s*([^>]*)\s*>/)
          //?properties?即?屬性字符串,即?class="header-box"?name="header"
          const?properties?=?mt[1]
          復(fù)制代碼

          取到了 class="header-box" name="header" 之后,再對其進(jìn)行處理,觀察規(guī)律,每個(gè)屬性的鍵值對之間肯定存在空白符,不過卻不能通過空白符來直接分割,因?yàn)閷傩灾凳强梢源嬖诳瞻追模?class="a b"

          由于可能是自閉合標(biāo)簽,自閉合標(biāo)簽的最后有沒有 / 都是合法的,例如


          hr />都是合法的,所以需要兼容下:/<\w+\s*([^>]*)\s*\/?>/

          但屬性名是可以確定的,它可能是 = 左邊不包括空白符的內(nèi)容,再次用到反向選擇,從左往右匹配,反向選擇既不是=也不是不是空白符的內(nèi)容,即 [^\s=]+

          雖然不確定屬性值是否包含空白符,但有個(gè)是確定的,即屬性值必然被引號包圍,所以直接取 = 右側(cè)所有引號的內(nèi)容即可,=".*?"

          不過還有個(gè)問題,引號不僅可以是單引號還可以是雙引號,即 =".*?"='.*?' 都行,如果第一個(gè)引號是雙引號開頭那么對應(yīng)的第二個(gè)引號也必然是雙引號,反義單引號亦然,這里需要用到捕獲的規(guī)則了 =(["']).*?\1\1的意思是這塊匹配的內(nèi)容跟第一捕獲組一樣,第一捕獲組也就是 ["'],如果第一捕獲組匹配的是雙引號,那么 \1 就代表雙引號,否則就代表單引號

          至此整個(gè)正則為 [^\s=]+=(["']).*?\1

          不過還有個(gè)問題,屬性是可以沒有屬性值的,例如 ,這里 checked 就是可以不寫屬性值的,所以再兼容下:/[^\s=]+(=(["']).*?\2)?/,又因?yàn)橄M蹲綄傩院蛯傩灾担越o屬性和屬性值加個(gè)小括號:/([^\s=]+)(=(["'])(.*?)\3)?/

          上面的代表就可以繼續(xù)寫了

          const?str?=?``
          const?mt?=?str.match(/<\w+\s*([^>]*)\s*>/)
          //?properties?即?屬性字符串,即?class="header-box"?name="header"
          const?properties?=?mt[1]
          const?mt1?=?properties.match(/([^\s=]+)(=(["'])(.*?)\3)?/g)
          const?obj?=?{}
          if?(mt1)?{
          ??mt1.forEach(p?=>?{
          ????const?kv?=?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ì)了,沒什么訣竅,無非就是對正則規(guī)則的熟練掌握罷了


          關(guān)于本文

          作者:清夜

          https://juejin.cn/post/7073360739410378760


          最后


          歡迎關(guān)注【前端瓶子君】??ヽ(°▽°)ノ?
          回復(fù)「算法」,加入前端編程源碼算法群!領(lǐng)取最新最熱的前端算法小書、面試小書以及海量簡歷模板,期待與你共進(jìn)步!
          回復(fù)「交流」,吹吹水、聊聊技術(shù)、吐吐槽!
          回復(fù)「閱讀」,每日刷刷高質(zhì)量好文!
          如果這篇文章對你有幫助,在看」是最大的支持
          ?》》面試官也在看的算法資料《《
          “在看和轉(zhuǎn)發(fā)”就是最大的支持



          瀏覽 37
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  录相一级毛片 | 亚洲日韩人妻蜜臀专区无码 | 亚洲成人情趣大香蕉视频 | 特级欧美AAAAAA | 黄片视频在线播放 |