<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在講正規表示式前,我們不妨先從一個場景來逐漸引入。
你可能有過這樣的經歷:我們去某些網站註冊帳號,當你在設定密碼的時候,網站會提示你密碼的長度範圍,以及對應的規則限制(如下圖)。
根據上圖,我們將密碼設定規則可以描述為兩個條件:
(1)長度為6-16位元;
(2)密碼中必須包含數位,大寫字母,小寫字母,特殊字元(指定字元);
現在假設我們不知道正規表示式,作為程式設計師的你,該如何去實現這樣一個密碼驗證呢?
下面是我寫的一個校驗方法(樣本):
/** * 校驗使用者密碼是否滿足設定規則 * * @param password 使用者輸入的密碼 * @return true-滿足;false-不滿足 */ public static boolean checkPassword(String password) { // 密碼不能為空 if (password == null || password.isEmpty()) { return false; } // 校驗密碼長度(6-16位元) int len = password.length(); if (len < 6 || len > 16) { return false; } // 定義四種組合條件 boolean hasNumber = false; boolean hasSmallLetter = false; boolean hasBigLetter = false; boolean hasSpecialChar = false; // 將密碼字串拆分為單個字元,然後對每個字元進行校驗 char[] chars = password.toCharArray(); for (char c : chars) { // 是否包含數位0-9 if (c >= '0' && c <= '9') { hasNumber = true; continue; } // 是否包含小寫字母a-z if (c >= 'a' && c <= 'z') { hasSmallLetter = true; continue; } // 是否包含大寫字母A-Z if (c >= 'A' && c <= 'Z') { hasBigLetter = true; continue; } // 是否滿足指定的特殊字元 if ("~@#S%*_-+=:.?".indexOf(c) > 0) { hasSpecialChar = true; continue; } // 如果某個字元不在上面四種情況,則不滿足規則 return false; } // 如果四種組合條件均滿足,則符合密碼設定規則 return hasNumber && hasSmallLetter && hasBigLetter && hasSpecialChar; }
這個方法寫得對不對呢?我們不防用幾組密碼去進行驗證下:
可以看到,我們列舉的8組密碼,都得到了驗證,說明我們的方法是OK的。
但這樣一個密碼設定規則校驗,我們就差不多寫近 30 行的程式碼,是不是感覺有點累贅了呢?明明規則很簡單,程式碼量卻寫了這麼多,有沒有什麼方法可以簡化我們的程式碼呢?當然有!於是,這時就可以讓我們今天的主角正規表示式出場了。
下面,則是具有相同校驗功能,基於正規表示式的驗證方法:
/** * 通過正規表示式校驗使用者密碼是否滿足設定規則 * * @param password 使用者輸入的密碼 * @return true-滿足;false-不滿足 */ public static boolean checkPasswordByRegex(String password) { return Pattern.matches("^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[~@#S%*_\-+=:.?])[A-Za-z0-9~@#S%*_\-+=:.?]{8,20}$", password); }
那麼它寫得到底對不對呢?於是,我們可以通過上面的範例資料,繼續呼叫該方法來進行驗證:
通過結果我們可以看到,他也是符合我們預期的。於是我們發現,在不用正規表示式的時候,我們的程式碼量近30行,而使用了正規表示式,程式碼就濃縮為了1行,也就是說,使用正規表示式時可以簡化我們的程式碼。
但同時我們也可知,正規表示式具有一定的學習成本,如果你不懂正規表示式,那麼你看它可能就是一頭霧水,如果出了問題,更也就無從下手去修改它了。
所以,學會正規表示式還是有必要的,至少以後你的同事寫出來後,不會在腦子裡出現 "這是寫的啥玩意兒啊?怎麼我看不懂" 的想法。
什麼是正規表示式?通過上面的案例大家可能多少有點了解了。是的,他就是通過一行字串,來描述一定的規則(如下圖箭頭所指紅框處)。
正規表示式的英文為 Regular Expression,所以我們通常採用這兩個單詞的首幾個字母合在一起,把正規表示式相關的變數名定義為 regexp(單數) 或 regexps(複數) 。
比如:
又比如,在 Java 的 String 類中,有幾個相關替換的方法,它也是支援正規表示式的,他的引數命名也是 regex 。
正規表示式通常由一些普通字元,以及一些元字元組成。
普通字元:就是本身作為一個字元時,它不具有其他含義,像我們常用的大小寫字母和數位。
元字元:就是除了本身作為一個字元外,他還可以表達其他含義(下圖是部分元字元節選)。
其實,我們學習正規表示式,大部分就是基於元字元的學習。
學習了正規表示式,我們可以有哪些用途場景呢?
(1)做字串的規則驗證(比如前面的案例引入中,我們可以通過正規表示式來驗證一個密碼是否符合規則)。
(2)做字串的替換(比如將一個字串中所有的大小寫字母去掉,或者替換為指定符號)。
(3)提取字串中所需要的字元(比如一個字串中所有的數位提取出來,組成一個新的字串)。
正規表示式主要用途就是校驗字串,那麼在Java中,只需要通過下面這個方法即可進行校驗。
boolean result = Pattern.matches(regex, input);
其中:
regex 是我們需要寫的正規表示式校驗規則;
input 是我們待校驗的字串;
返回的 result 就是我們校驗的結果,當為 true 的時候,表示校驗通過,當為 false 的時候,則表示校驗不通過。
當我們的正規表示式為一串普通字元(不包含元字元)時,校驗字串只有和正則一致時,才會校驗通過。
具體效果如下:
說明:後面例子為節省篇幅,不顯得累贅,就不再貼程式碼,只貼校驗結果。
d 表示一個數位。
如:
aaad: 表示驗證的字串後面必須以 aaa 開頭,且以一個數位結尾。
aaadbbb:aaa和bbb中間有一個數位
aaadd:aaa後面跟2個數位
注意:在Java定義的正則裡,由於一個表示的是字串跳脫,因此在Java定義帶有的元字元時,還需要多寫一個,即\,至於其他語言,自己可查閱相關資料進行了解。
D 表示一個非數位,它和上面 d 的意思恰好相反。
如:
DDD: 則表示一個長度為3,不包含數位的字串。
111D222:則表示111和222中間,必須包含一個非數位。
w 表示一個字母(大小寫均可)、數位,或下劃線。
如:
12w45:則表示12和45中間必須是一個字母,數位,或下劃線。
W 與 w 相反,表示這個位置的字元既不是字母、數位,也不是下劃線。
也就是:特殊符號(除下劃線),或者空格等滿足。
如:
12w45:則表示12和45中間是一個非字母,非數位,或非下劃線。
s 表示匹配一個看不見的符號,即空格或製表符(Tab鍵)
如:
88s99:則表示88和99中間須是一個空格或製表符。
(由於我的編輯器設定了1個製表符替換為4個空格,所以這裡就不列舉製表符情況了)
正則:S
S 與 s 相反,表示一個可以看得見的符號。
如:
88S99:則表示88和99中間須有一個看得見的符號。
正則:.
. (小數點) 則表示“n”和"r"之外的任何單個字元。
如:
.... :則表示任意四個字元
正則:|
| (豎線) 則表示或的關係,表示檢測的字串須滿足其中一個時,才符合條件。
如:
aa|bb|cc:則表示輸入的字串須是aa,或bb,或cc其中的一個。
注意,如果我們或者關係的前後還有其它字元時,需要用()將他們包裹起來。
如:
xx(aa|bb|cc)yy:則表示輸入的字串須是xx開頭,yy結尾,且中間是aa,或bb,或cc其中的一個。
正則:[abc]
[ ] 表示匹配其中任意一個字元。
如:
a[bcd]e:則表示a和e的中間須是b,或c,或d其中的一個
注意:用 | 表示其中之一,他可以是字元,也可以是字串。而只用中括號時,則只表示其中一個字元。
[^ ] 表示不與中括號裡的任意字元匹配。
如:
a[^bcd]e:則表示a和e的中間除b,c,d這三個字元外,其他的字元都滿足。
[值1-值2] 則表示值1到值2中間的所有字元都滿足(包括值1和值2)。常用該正則來表示大小寫字母範圍,數位範圍。
如:
a[b-d]e:等同於 a[bcd]e,因為 b-d 其實就是b,c,d三個數。
a[0-9]e:則表示a和e中間是一個數位,等同於 ade(前面說過d表示一個數位)
[^值1-值2] 則表示除值1和值2之外的所有字元,都可以滿足。
如:
a[^1-3]e:則表示a和e中間的字元,只要不是1,2,3,則都滿足。
這裡的num指number,也就是數位,當後面跟數位,表示匹配第幾個括號中的結果。
比如:現在有 abcd 字串,當我們用小括號把 c 包裹起來後,然後在字串後面寫上 1,即 ab(c)d1,則這裡的 1 就指 c,因為 1 表示第1個小括號中的結果。
ab(c)d1:等同於 abcdc 。
如果我們繼續把 ab(c)d1 中的 d 包括起來,並在後面寫上 2,即 ab(c)(d)12, 那麼這裡的 2 就表示 d 這個字元,因為第2個小括號的結果是 d,所以整個表示式就等同於 abcdcd 。
ab(c)(d)12:等同於 abcdcd,也等同於 ab(cd)1 。
? 表示匹配前面的子表示式零次或一次。
如:
abc?de: 表示可匹配的字串為 abde (匹配0次c) 或 abcde (匹配1次c)。
匹配前面的子表示式一次或多次 (次數 >= 1,即至少1次)
如:
abc+de:ab 和 de 之前至少有一個 c 。
這裡的 n 是一個非負整數。匹配確定的前面的子表示式 n 次。
如:
abc{3}de:表示 ab 和 de 之間有3個c。
ab(xx|yy){3}de:表示 ab 和 de 之間有 xx 或 yy 的個數, 一起合計為3個。
m和n均為非負整數,其中 n<=m。最少匹配 n 次且最多匹配 m 次。
如:
abc{2,3}de:表示 ab 和 de 之間有 2 到 3 個 c。
表示匹配前面的子表示式任意次。
如:
abc*de:表示 ab 和 de 之間有任意個數(包括0)c 。
到此這篇關於正規表示式教學的文章就介紹到這了,更多相關一看就懂正規表示式內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45