正則表達式實踐篇
- 與搜索字符串開始處的 3 個數字匹配: /^\d{3}/ 。
- 與除 a、b 和 c 以外的任何字符匹配: /[^abc]/ 。
- ‘1234567’.match(/\d{1,3}/g),根據貪婪原則,結果是 ["123", "456", "7"] 。
- 不以“th”開頭的單詞匹配: /\b(?!th)\w+\b/ 。
- 對密碼應用以下限制:其長度必須介于 4 到 8 個字符之間,并且必須至少包含一個數字: /^(?=.*\d).{4,8}$/ 。首先.{4,8} 表示與包含 4-8 個字符的字符串匹配;然后.*表示單個字符(除換行符 \n 外)零次或多次,且后面跟著一個數字,注意(?=)只匹配一個位置。
- 匹配一個中文字符: /[\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點。
因此有三個多選分支,得到的結果為:
0?[0-9]|1[0-9]|2[0-3]
還可以優化一下,合并前面的兩個多選分支,得到:
[01]?[0-9]|2[0-3]
方法二:分類邏輯為第二個數字,可以分為兩部分:[0-3]和[4-9]。為什么這么分?看看下面這個圖就知道了,[0-3]多了一行(以2為第一個數字):
因此有兩個多選分支,結果為:
[012]?[0-3]|[01]?[4-9]
-
分鐘部分
分鐘數比較簡單,第一個數范圍在0-5之間,第二個數在0-9之間,因此得到分鐘數為:
[0-5][0-9]
-
最后的結果:
小時部分用(?:)包起來,起到一個分組的作用,且不保存匹配項;
冒號、分鐘數拼起來;
最后加上一個分界 \b 表示單詞的開始或結束,得到最終的結果:
/\b(?:[01]?[0-9]|2[0-3]):[0-5][0-9]\b/
// 或者
/\b(?:[012]?[0-3]|[01]?[4-9]):[0-5][0-9]\b/
-
驗證:
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。
從上面的陳述中我們就可以得到三個多選分支:
\d|\d\d|[01]\d\d
我們稍微合并一下這三個多選分支,得到:
[01]?\d\d?
-
第二步:
我們再來看以2開頭的三位數:
第二位數小于5的時候,第三位數范圍[0-9]都可以;第二位數等于5的時候,第三位數范圍[0-5] ,因此得到兩個多選分支:
2[0-4]\d|25[0-5]
-
第三步:
前兩步合并起來,得到一個字段0-255的表示方法:
[01]?\d\d?|2[0-4]\d|25[0-5]
-
第四步:
四個字段合并起來,IP地址正則如下:
/^(?:[01]?\d\d?|2[0-4]\d|25[0-5])\.(?:[01]?\d\d?|2[0-4]\d|25[0-5])\.(?:[01]?\d\d?|2[0-4]\d|25[0-5])\.(?:[01]?\d\d?|2[0-4]\d|25[0-5])$/
點號要轉義一下,^和$需要加上,否則可能匹配52123.3.22.993,因為其中的123.3.22.99是符合的。(?:)起到分組的作用,且不保存匹配項。
一些測試結果:
var reg = /^(?:[01]?\d\d?|2[0-4]\d|25[0-5]).(?:[01]?\d\d?|2[0-4]\d|25[0-5]).(?:[01]?\d\d?|2[0-4]\d|25[0-5]).(?:[01]?\d\d?|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"]
</code></pre>
雖然0.0.0.0是合法的,但它是非法的IP地址,使用正則的否定順序環視功能(零寬負向先行斷言),可加上(?!0+.0+.0+.0+$) :
var reg = /^(?!0+.0+.0+.0+$)(?:[01]?\d\d?|2[0-4]\d|25[0-5]).(?:[01]?\d\d?|2[0-4]\d|25[0-5]).(?:[01]?\d\d?|2[0-4]\d|25[0-5]).(?:[01]?\d\d?|2[0-4]\d|25[0-5])$/;
'123.11.22.33'.match(reg); // ["123.11.22.33"]
'0.0.0.0'.match(reg); // null
</code></pre>
來自:https://aotu.io/notes/2016/12/07/regexp-practice/