亚洲综合小说另类图片

<dfn id="4z7un"><s id="4z7un"></s></dfn>
          1. <nav id="4z7un"><sup id="4z7un"></sup></nav>
            <th id="4z7un"></th>

          2. <output id="4z7un"><small id="4z7un"><input id="4z7un"></input></small></output>
            八周年活動月
            歡迎訪問長沙友點軟件科技有限公司旗下產品友點CMS官方網站!
            友點CMS

            精通正則表達式

            來源:友點CMS 日期:2019-07-02 14:10:58 屬于:其它

            簡單的練習:

            題目

            1.與搜索字符串開始處的 3 個數字匹配。
            2.與除 a、b 和 c 以外的任何字符匹配。
            3.'1234567'.match(/d{1,3}/g)的結果。
            4.不以“th”開頭的單詞匹配。
            5.對密碼應用以下限制:其長度必須介于 4 到 8 個字符之間,并且必須至少包含一個數字。
            6.匹配一個中文字符。

            答案

            1.與搜索字符串開始處的 3 個數字匹配:/^d{3}/。
            2.與除 a、b 和 c 以外的任何字符匹配: /[^abc]/。
            3.‘1234567’.match(/d{1,3}/g),根據貪婪原則,結果是 ["123", "456", "7"]。
            4.不以“th”開頭的單詞匹配:/b(?!th)w+b/ 。
            5.對密碼應用以下限制:其長度必須介于 4 到 8 個字符之間,并且必須至少包含一個數字: /^(?=.*d).{4,8}$/ 。首先.{4,8} 表示與包含 4-8 個字符的字符串匹配;然后.*表示單個字符(除換行符 n 外)零次或多次,且后面跟著一個數字,注意(?=)只匹配一個位置。
            6.匹配一個中文字符:/[u4e00-u9fa5]/。

            當然,可能答案不唯一,不必較真啦~ 主要目的是回憶熟悉一下語法~
             

            真正的實踐來了

            要想在復雜性和完整性之間取得平衡,一個重要因素是要了解將要搜索的文本。
            好的正則表達式:

            只匹配期望的文本,排除不期望的文本;
            易于控制和理解;
            保證效率。

            有時候處理各種極端情況會降低成本/收益的比例。所以某些情況下,不完全依賴正則表達式完成全部工作,比如某些字段用子表達式()括起來,讓內存記憶下來,然后再用其他程序來驗證。

            不過本文還是從學習正則的角度出發,全部依賴正則表達式來寫的哇~~

            匹配美元

            正則表達式:/^$[0-9]+(.[0-9][0-9])?$/。

            分為四部分:

            ^$ 以美元符號開頭。
            [0-9]+ 至少包含一個數字。
            (.[0-9][0-9])? 由一個點和兩位數組成,匹配0次或1次,因為可能是整數或者是小數。
            $ 最后的$表示以數字結尾的。

            缺點:不能匹配$1,000

            匹配24小時制的時間,比如 09:59

            小時部分

            方法一:分類邏輯為第一個數字(0、1、2),可以分為三部分:上午 00點到09點(0可選);白天10到19點;晚上20到23點。

            因此有三個多選分支,得到的結果為:

            1
            
            			
            0?[0-9]|1[0-9]|2[0-3]
            
            			

            還可以優化一下,合并前面的兩個多選分支,得到:

            1
            
            			
            [01]?[0-9]|2[0-3]
            
            			

            方法二:分類邏輯為第二個數字,可以分為兩部分:[0-3]和[4-9]。為什么這么分?看看下面這個圖就知道了,[0-3]多了一行(以2為第一個數字):

            24hour

            因此有兩個多選分支,結果為:

            1
            
            			
            [012]?[0-3]|[01]?[4-9]
            
            			

             

            • 分鐘部分

            分鐘數比較簡單,第一個數范圍在0-5之間,第二個數在0-9之間,因此得到分鐘數為:

            1
            
            			
            [0-5][0-9]
            
            			
            最后的結果:

            小時部分用(?:)包起來,起到一個分組的作用,且不保存匹配項;
            冒號、分鐘數拼起來;
            最后加上一個分界b表示單詞的開始或結束,得到最終的結果:

            1
            2
            3
            
            			
            /b(?:[01]?[0-9]|2[0-3]):[0-5][0-9]b/
            // 或者
            /b(?:[012]?[0-3]|[01]?[4-9]):[0-5][0-9]b/
            
            			
            驗證:
            1
            2
            3
            
            			
            var reg = /b(?:[01]?[0-9]|2[0-3]):[0-5][0-9]b/;
            '現在是09:49點'.match(reg);	// ["09:49"]
            '現在是009:490點'.match(reg);	 // null
            
            			

            其實這個結果不能說完全正確,首先你要明白這個正則用在什么地方,比如是數據驗證或者
            復雜的字符串搜尋替換。

            情景一:填寫表單中的字符串必須為24小時制的時間,那么可能第一個b需要改成^,第二個b改成$。

            情景二:用于復雜的字符串搜尋替換時,可能也會匹配這樣子的字符串如’跑步用時19:50’,明顯的,’19:50’表示19分50秒,而不是表示24小時制的時間19點50分。

            匹配IP地址

            IP地址的規則:點號分開的四個字段,每個字段在0-255之間。

            第一步:

            如果一個字段是一個數或兩個數,肯定是在0-255的范圍內的;
            如果三位數,那么以0或者1開頭的三位數也是合法的,即000-199。

            從上面的陳述中我們就可以得到三個多選分支:

            1
            
            			
            d|dd|[01]dd
            
            			

            我們稍微合并一下這三個多選分支,得到:

            1
            
            			
            [01]?dd?
            
            			
            第二步:

            我們再來看以2開頭的三位數:

            第二位數小于5的時候,第三位數范圍[0-9]都可以;第二位數等于5的時候,第三位數范圍[0-5] ,因此得到兩個多選分支:

            1
            
            			
            2[0-4]d|25[0-5]
            
            			
            第三步:

            前兩步合并起來,得到一個字段0-255的表示方法:

            1
            
            			
            [01]?dd?|2[0-4]d|25[0-5]
            
            			
            第四步:

            四個字段合并起來,IP地址正則如下:

            1
            
            			
            /^(?:[01]?dd?|2[0-4]d|25[0-5]).(?:[01]?dd?|2[0-4]d|25[0-5]).(?:[01]?dd?|2[0-4]d|25[0-5]).(?:[01]?dd?|2[0-4]d|25[0-5])$/
            
            			

            點號要轉義一下,^和$需要加上,否則可能匹配52123.3.22.993,因為其中的123.3.22.99是符合的。(?:)起到分組的作用,且不保存匹配項。

            一些測試結果:

            1
            2
            3
            4
            5
            6
            
            			
            var reg = /^(?:[01]?dd?|2[0-4]d|25[0-5]).(?:[01]?dd?|2[0-4]d|25[0-5]).(?:[01]?dd?|2[0-4]d|25[0-5]).(?:[01]?dd?|2[0-4]d|25[0-5])$/;
            
            '123.11.22.33.44'.match(reg); // null
            '52123.3.22.993'.match(reg);  // null
            '123.11.22.33'.match(reg);  // ["123.11.22.33"]
            '0.0.0.0'.match(reg); 	// ["0.0.0.0"]
            
            			

            雖然0.0.0.0是合法的,但它是非法的IP地址,使用正則的否定順序環視功能(零寬負向先行斷言),可加上(?!0+.0+.0+.0+$) :

            1
            2
            3
            4
            
            			
            var reg = /^(?!0+.0+.0+.0+$)(?:[01]?dd?|2[0-4]d|25[0-5]).(?:[01]?dd?|2[0-4]d|25[0-5]).(?:[01]?dd?|2[0-4]d|25[0-5]).(?:[01]?dd?|2[0-4]d|25[0-5])$/;
            
            '123.11.22.33'.match(reg); // ["123.11.22.33"]
            '0.0.0.0'.match(reg);  // null
            
            			

            匹配分隔符之內的文本

            常見的匹配要求

            匹配/**/之間的css注釋。
            匹配引文字符串””,且容許其中包含轉義的引號”。
            匹配一個HTML tag,也就是尖括號之內的文本,例如。

            匹配思路的步驟

            1.匹配起始分隔符。
            2.匹配正文(即結束分隔符之前的所有文本)。
            3.匹配結束分隔符。

            容許引文字符串中出現轉義引號

            大概思路

            描述:起始分隔符和結束分隔符都是",且正文中容許出現轉義之后的引號"。

            簡單情況分析:

            舉例:匹配類似 I "start "x3" end" U 文本的 "start "x3" end" 引文字符串,注意"屬于轉義引號。

            起始分隔符和結束分隔符都是"。
            字符不是引號,肯定是正文。即[^"]表示不是引號的其他任意字符。
            引號"前面有反斜線,且被反斜線轉義,則也屬于正文。例如start"引號的前面有一個反斜線,那么這個引號也屬于正文。即(?<=)”表示匹配一個引號,它的前面有一個,注意正則的反斜線也要用來轉義一下,因為是特殊字符。

            用非捕獲分組(?:)[^"]|(?<=)"括起來,給個量詞*,表示匹配正文0次或多次。
            因此可以寫出正則表達式: /"(?:[^"]|(?<=)")*"/
            注意:ES7才支持逆序環視(?<=)

            驗證1:

            驗證正則:/"(?:[^"]|(?<=)")*"/

            1
            2
            3
            4
            5
            
            			
            'I "start "x3" end" U'.match(/"(?:[^"]|(?<=)")*"/);
            // 結果: [""start ""]
            
            'I "start "x3" end" U'.match(/"(?:[^"]|(?<=)")*"/);
            // 結果:[""start "x3" end""]
            
            			

            為什么第2個才是對的呢?我們看一下返回的input屬性就了解了:

            input屬性

            驗證2:

            驗證正則:/"(?:[^"]|(?<=)")*"/

            1
            2
            3
            4
            
            			
            'I "start "x3" end" U'.match(/"(?:[^"]|(?<=)")*"/);
            // 結果與期望不符合:[""start "x3" end""]
            // 期望:[""start"x3"]
            // 注意返回的input屬性為:"I "start "x3" end" U"
            
            			

            引號”前面有反斜線,但是這個反斜線不是轉義引號的,那么引號就不應該屬于正文,而是屬于結束分隔符。
            什么情況反斜線不轉義引號呢?
            這個反斜線本身就是被轉義的情況。

            上面的結果按照預期結果應該返回 [""start"x3"],但是現在多了end"。
            因此驗證這個正則表達式不正確。

            也就是說,正文中可出現轉義的字符,因此得出正則. ,注意第一個表示轉義第二個,點表示匹配除換行符 n 之外的任何單個字符),例如可以匹配+或者。而且轉義的字符已經包含了"的情況,因此正則(?<=)"可以不用寫了,且替換成.。

            因此改正后的正則:/"(?:.|[^"])*"/

            你可能注意到了,我把[^”]和.的位置調換一下,后面的驗證3會講到為什么要這么做。

            驗證3:

            驗證正則:/"(?:.|[^"])*"/ 和 /"(?:[^"]|.)*"/

            1
            2
            3
            4
            5
            6
            7
            8
            9
            
            			
            'I "start "x3" end" U'.match(/"(?:.|[^"])*"/);
            // 結果與期望符合:[""start "x3""]
            // input: "I "start "x3" end" U"
            
            // [^"]和.的位置調換
            'I "start "x3" end" U'.match(/"(?:[^"]|.)*"/);
            // 結果與期望不符合:[""start ""]
            // 期望:[""start"x3"]
            // input: "I "start "x3" end" U"
            
            			

            [^"].的位置調換后,結果與期望不符合。那是因為[^"]匹配start 后,遇到緊接著的"不匹配,交給后面的多選分支.,也不匹配,又剛好結束分隔符是",導致匹配成功,結束匹配。

            因此兩個正則之間 正確的正則是 /"(?:.|[^"])*"/

            驗證4:

            驗證:/"(?:.|[^"])*"/

            1
            2
            3
            4
            
            			
            'I "start "x3" end U'.match(/"(?:.|[^"])*"/);
            // 結果與期望不符合:[""start "x3""]
            // 注意end后面少了",期望結果是null,不匹配
            // input: "I "start "x3" end U"
            
            			

            上面的字符串 "start"x3" 其實是沒有結束分隔符的,但是還是匹配了。那是因為正則[^"]. 一起作用,導致匹配到了文本U末尾,后續想找結束分隔符的時候,結果卻找不到,所以只能回溯文本去找結束分隔符,最后找到了 x3后面的引號,匹配成功,結束匹配。

            回溯會導致不期望的結果,由于是卡在多選分支上出錯的,因此猜測多選分支|匹配內容出現重疊。

            你想想,如果符合正文的反斜線,不是以[^"]方式匹配,而是以.的方式匹配,那就不會把好好的"拆開來匹配了。

            綜上所述,一定要讓反斜線是以.的方式匹配,字符串里的反斜桿不能以[^"]方式匹配。
            因此將[^"]改成[^"]。這樣子就可以確保正確識別正文特殊的"和結束分隔符"了。

            注意:很多字符在[]都會失去本來的意義,但是反斜杠字符  仍為轉義字符。若要匹配反斜杠字符,請使用兩個反斜杠 。

            改正的正則:/"(?:.|[^"])*"/

            驗證5

            驗證:/"(?:.|[^"])*"/

            1
            2
            3
            4
            5
            6
            7
            8
            
            			
            'I "start "x3" end U'.match(/"(?:.|[^"])*"/);
            // 結果與期望符合:null
            // input: "I "start "x3" end" U"
            
            
            'I "start "x3" end" U'.match(/"(?:.|[^"])*"/);
            // 結果與期望符合:[""start "x3" end""]
            // input: "I "start "x3" end" U"
            
            			

            為了優化,我們可以把[^"]放在前面,因為普通字符的匹配可能性更大。
            注意:優化正則提高效率最需要考慮的問題:改動是否會影響匹配。只有在排序與匹配成功無關時才不會影響準確性,才能重新安排多選分支的順序。

            優化后的正則:/"(?:[^"]|.)*"/

            HTML Tag

            經歷了容許引文字符串中出現轉義引號的例子分析,瞬間覺得這個容易了許多。
            描述與要求:匹配類似<input name=123 value=">" >的HTML標簽,起始分隔符是<,結束分隔符是>,且HTML 標簽屬性值中可以出現>。
            起始分隔符和結束分隔符都是明確的,我們來分類一下正文。
            雙引號引用文本
            單引號引用文本
            除了>和引號之外的任意字符
            可能你會當心單雙引號引用文本,會像“容許引文字符串中出現轉義引號”那么復雜。幸好是HTML Tag的屬性值中不允許出現轉義引號,因為平常的轉義符號變成了普通字符。
            根據三種情況,分別寫出三個正則:
            "[^"]*"
            '[^']*'
            [^'">]
            好了,用多選分支連起來"[^"]*"|'[^']*'|[^'">],再用非捕獲分組(?:)將多選分支括起來,如(?:"[^"]*"|'[^']*'|[^'">]),用*表示匹配任意次,最后前后加上開始結束分隔符,搞定:/<(?:"[^"]*"|'[^']*'|[^'">])*>/
            驗證:
            1'<input name=123 value=">" >'.match(/<(?:"[^"]*"|'[^']*'|[^'">])*>/)
            2// 結果: ["<input name=123 value=">" >"]

             
            相關文章
              暫無信息
            亚洲综合小说另类图片
            <dfn id="4z7un"><s id="4z7un"></s></dfn>
                    1. <nav id="4z7un"><sup id="4z7un"></sup></nav>
                      <th id="4z7un"></th>

                    2. <output id="4z7un"><small id="4z7un"><input id="4z7un"></input></small></output>