\[a-zA-z]{3,}|^\D$|^[0-9a-z]*$|^[0-9A-Z]*$\
相信大家在寫程式的過程當中,一定都曾看到過像上面這種,有點像亂寫的程式碼,有些可能看起來沒那麼複雜,而有些則是長到讓人難以招架,光是看到就讓人頭痛,更不用說去讀懂它了。
事實上,這種程式碼叫做正規表達式(RegExp,Regular Expression),是處理文字非常重要的利器,當你希望規範文字的格式、或者是限制使用者的文字格式時,正規表達式是不可或缺的存在。
文首的表達式是我超級討厭的銀行密碼格式(還有 PlayStayion Network 的密碼格式),會找出這些格式:
- 超過連續三個英文字母(不分大小寫)
- 沒有任何數字
- 沒有任何大寫字母
- 沒有任何小寫字母
只要你設立的密碼符合以上任何一個格式,程式就會拒絕你使用這組密碼,以這樣的方式來讓使用者建立出一個安全性相對高的密碼——雖然很多時候都是徒勞無功的。
在這篇文章當中,希望可以透過簡單明瞭的方式來講解正規表達式,並且讓大家在未來撰寫或閱讀正規表達式的時候,能夠得心應手,無所畏懼。
在 Ruby 裡面,有幾種方式可以定義正規表達式,比較普遍的方式是用 slash(/) 將正規表達式包起來,像是 /[a-zA-Z]*/
,而另一種方式則是用 Ruby 的 class生成,變成、 Regexp.new('[a-zA-Z]*')
,值得注意的是,使用第二種方式不需要加入 slash,只要將內容以字串方式傳入即可。大部分情況下我們會看到第一種方式,少部分的情況下,特別是需要動態產生正規表達式的時候,第二個方式會比較好用。最後則是將利用 %r{[a-zA-Z]*}
這樣的方式也可以定義正規表達式。
使用 %r 的情況下,不需要將 {} 裡面的表達式包成字串
在正規表達式當中,我們有幾個比較常用的 Match Character 來表示我們的規則:
Match Character | 規則 |
---|---|
. | 所有字元 |
\w | 所有字母,包含大小寫跟數字 |
\d | 所有數字(0-9) |
\D | 除了數字以外的字元 |
[ ] | 指定的範圍,例如[a-f] |
當然,只有 Match Character 還不夠,我們還必須指定字元是否重複,或者重複的次數,否則預設都是一個字元。
重複表示 | 規則 |
---|---|
? | 未出現或出現一次 |
* | 未出現或出現多次 |
+ | 出現一次或多次 |
{a} | 出現 a 次 |
{a,} | 至少出現 a 次以上 |
{,b} | 最多出現 b 次 |
{a,b} | 最少出現 a 次,最多出現 b 次 |
舉個例子來說,台灣的市話號碼有可能是七碼或者八碼,我們就可以利用 {a, b} 這個重複規則來做出正確的格式:/^\d{7, 8}$/
。這個正規表達式的意思,我們希望找出一個有七到八個數字的字串,而前面的 ^
以及後面的 $
分別代表字串的開頭開始和字串的結尾,這在很多場合是非常重要的。假設沒有規定必須從字串的最前面開始或在最後結束,他便會抓取最前面或是最後面符合的字串,如此一來便不符合我們希望的規則。
舉例來說,如果我們的規則是這樣 /^\d{7, 8}/
,沒有最後結束的符號,那麼即使當我輸入手機號碼 0955555555,他還是會回傳最前面的八位數字給你。
# incorrect
pry(main)> '09555555555'.match /^\d{7,8}/
=> #<MatchData "09555555">
# correct
pry(main)> '09555555555'.match /^\d{7,8}$/
=> nil
如此一來我們可以回頭看一開始的表達式
\[a-zA-z]{3,}|^\D$|^[0-9a-z]*$|^[0-9A-Z]*$\
這邊可以注意到,中間我們用 pipe |
來做分隔,其實 pipe 就是 or 的意思,我們可以利用這個方式來加入多個條件,因此我們也可以將表達是分開來解讀。
[a-zA-Z]{3,}
這個部分則表示我們要找出無論大寫或是小寫的字母,三個連續字母連在一起的組合。^\D$
這裡則表示找出整個字串都完全沒有數字的組合。^[0-9a-z]*$
這段則是找出整個字串中只有小寫和字母,意思就是字串中完全沒有大寫的組合。^[0-9A-Z]*$
和上面那段相似,只是找出沒有小寫的組合。
利用這個表達式,我們就可以順利做出一個討人厭的密碼規則囉,是不是很簡單呢?
在文章的最後,提供一個方便的線上工具,你可以在這個網頁上任意嘗試各種 RegExp 的組合,並且確認規則是否正確,非常地方便:http://rubular.com/
希望透過這篇文章,讓大家可以輕鬆地解讀正規表達式,並且也能夠順利地用正規表達式寫出簡潔的程式碼。
photo by Christiaan Colen