前言
> 上述是身為一個程式初心者在察找時, 搜到的普遍網路資料
> 為此小的發了個宏願
> 希望能產出一篇淺顯易懂且趣味性高的故事教學
> 讓沒寫過程式和regex的Dummy也能快速理解上手
> 僅願能由此作為開端, 推廣regex的魅力
> 你是誰?
> 你叫什麼?
> 你在幹嘛?
> 你做什麼工作?
我叫小優,來自台灣、最喜歡吃章魚,
每天的工作是在這邊陪你打屁喇賽。
▼
來聊聊天吧
這都歸功於 正規表達式 (Regular Expression)。
為什麼這些問題都可以讓機器感應後、
以同一種答案回覆呢?
電腦是怎麼偵測到的?
什麼是正規表達式(Regular Expression)?
寫了數千行程式,才赫然發現…
天啊!不小心忘記”灰色”的英文怎麼拼了!
結果整份文件grey和gray亂拼一通。
> 你可能會說: 阿是不會用”尋找/取代”的功能膩
> 但除了grey和gray手殘拼錯之外
> ”Grey“, ”Gray“, ”GReY“, ”grey123“也亂拼了一堆
> 難道要用”搜尋/取代”功能到真的變成手殘嗎
別害怕, 讓我們開大絕
發動
正規表達式
(ㄏ ̄□ ̄)ㄏ 喔~~喔喔~~喔喔~~喔喔~~規規
> 想要同時找出“grey”和"gray"?
(灰色的格雷先生)
> 一行正規表達式瞬間了結
> gr[ae]y
> 等等我還有別的要求! 大小寫開頭都要!
(格雷先生要大寫阿!)
> 太天真了! 別小看正規表達式阿!!
> [Gg]r[ae]y
挖賽怎麼會有這麼好用的東西!
…但除此之外它還可以幹嘛
用處多多啊正規表達式ヽ(*´∀`)ノ
> 密碼 大小寫字母和數字的組合,且長度在8-12之間
> 身分證字號 英文開頭, 第二個數字必定為1或2, 後面接8個數字
> 手機號碼 09開頭,中間”-”符號可有可無, 如09**-***-***
> 日期 格式為YYYY-MM-DD, 且須考慮平閏年
若請你使用程式語言的”if/else條件句”達到下列目的:
/(?=.*u)(?=.*l)(?=.*d).{8,12}$/
(╯-_-)╯ ~╩╩ 馬的整人嗎, 寫到死吧
傻逼,沒聽過 用一行就能解決嗎Σ( ̄□ ̄)
而且他學起來可以一勞永逸ヽ(*´∀`)ノ
> 正規表達式不是程式語言也不是軟體, 只是一個邏輯式
> 多種程式語言都能支援JavaScript, Perl, Python, Java, C/C++
> 表示你只要學會一招就可以到處開大絕耶
> 他是1956年由數學家Stephen Kleene所提出
> 表示你學了之後可以用六十年耶!
> 好工具, 不衝嗎 ^_<
挖賽我怎麼沒有早一點知道這件事
…那我幹嘛不把所有程式都寫成正規表達式
((http[s]{0,1}|ftp)://[a-zA-Z0-9.-_/]+.([a-zA-
Z]{2,4})(:d+)?(/[a-zA-Z0-9.-
~!@#$%^&amp;*+?:_/=<>]*)?)(([0-9a-fA-F]{1,4}:){7,7}[0-9a-
fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-
fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-
fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-
F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-
9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-
F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-
F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-
5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-
4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-
4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-
9]){0,1}[0-9])) ^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-
9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-
複用更難 (正規表達式的數字式難以用在多個不同情境上)
Review難 (除了你自己之外其他人很難看懂啊! 誰要接手你的工作!)
Debug難 (你可能寫完都忘記自己是用甚麼邏輯寫成的了)
不是所有問題都要使用正規表達式。
大量、重複、簡單的文字處理,最好使用正規表達式。
一般人有三種東西看不懂──
醫生的處方,道士的鬼畫符,工程師的正規表達式
讓我們來開始正規表達式的學習吧
( ̄﹁ ̄) 終於開始進入正題了
學數學時,花了很多的時間精力背誦九九乘法表。
正規表達式的學習也是一樣。
初學者可以使用Regular Expression 101網站進行測試:
試著在//裡面輸入比對的規則、在Text String中填入需要比對的文本,
會發現:「為什麼只能找出一個字串?」
regex = /pattern/flag
正規表達式結構 = /比對規則/比對方式
因為你沒跟它講你的比對方式
舉例來說:
/cat/是以//雙引號將cat這個正規表達式框起來,cat是規則(pattern)。
沒設定比對方式的話,它只會比對一筆資料。
因此我們必須在/規則/外面加上比對方式(flag),
比如在/cat/外加上g、變成/cat/g,表示我們想要比對全部範圍的文本。
多說無益,直接來試試看吧!
最為常用的flag主要有兩個:
/pattern/g: 表示查詢全部文本 (global match)
/pattern/i: 表示不限大小寫 (ignore case)
若同時打上gi,表示要查
「文本中全部的單字」且「不限大小寫」。
flag根據不同的程式語言也有所不同,可在網站右下角找詢flag所代表的意思。
[] : 代表集合中的任一字元, 比如說[1,3,5,7]代表1,3,5或7任何一個字。逗點可省
略,[1,3,5,7]=[1357]。
- : 代表從...到的範圍,比如說[1-4]等於[1,2,3,4]。
{} : 代表字元出現次數, 比如a{2,7}表示a字元出現了2到7次。
() : 將比對符合的字元暫時存入一個變數, 供系統後續使用。比如(x) and (y)可以由 ‘xx
and yyy’字串比對出’xx’和’yyy’, 並將這兩個比對得到的字串暫存入RegExp.$1
和 RegExp.$2中, 讓系統後續在使用RegExp.$1 時即代表’xx’。
| : 代表或(or),比如ant|bug|worm代表ant或bug或worm其中之一皆可。
正規表達式可分成一般字元(Characters)與特殊字元(Operators),
一般字元指的是普通的文字,特殊字元則有特定的字元查詢功能。
下列是正規表達式中的特殊字元:
介紹完了flag, 來看看 pattern是怎麼寫成的吧!
. : 代表任意字元, 比如 .at可以符合cat, bat, rat等任意字元的開頭, 後面要接at。
^ : 代表字元在開頭位置, 比如^cat代表cat, catch與cathay皆符合。
$ : 代表字元在結束位置, 比如ind$代表kind, blind, wind皆符合。
<>: 代表查詢單字本身。^AT代表僅鎖死開頭, ATM和ATT4FUN都符合; 而AT$代表鎖
死結尾, PAT和BAT都符合。但如果要鎖死開頭和結尾, 只查「AT」這個單字, 可以寫成
^AT$, 或是<AT>。比如<mon>只能查mon,而在lemon、monster和admonish都
不符合。
[^]: 在括號內代表否定, 比如[^abcde]代表配對abcde以外的字元。
! : 代表條件相反的反向比對。比如a[!bc]代表只要不是ab或是ac, 其他都符合; ad即符合
a[!ab]。
背 背 背 背背背背
1. /[pf]our/代表什麼意思呢?
答: pour和four都符合配對。/[pf]our/同於/[p|f]our/或/[p,f]our/。
2. (a)7331 (b)73331 (c)733331 (d)7333331;
哪些選項符合/73{2,4}1/?
答: (a)(b)(c)符合。
3. (a)8ap9We (b)mU3 (c)Zom0 (d)KeD5;
哪些選項符合/[k-q].[^4-7]/呢?
答: (a)p9W,(b)mU3,(c)om0。故(a)(b)(c)皆符合。
小練習:(可使用Regular Expression 101進行測試)
? : 代表?前的字元可出現0次或1次, 比如bin?d的n可出現0次或1次, 同時符合bid和bind。
也等於n{0,1}。
+ : 代表+前面的字元可出現1次或多次, 比如Re+ally, 符合Really, Reealy, Reeeeealy ; e
至少出現一次。也等於e{1,}。
* : 代表*前面的字元可出現零次或多次, 比如go* 符合g 和gooooo。也等於g{0,}。
1. 請表達任意整數。如0, 17, 25189。
答: /^(0|[1-9][0-9]*)$/。
2. 請表達任意小數。如0.388, 73592.16。
答: /^([0-9]+.[0-9]+)$/。
小練習:(可使用Regular Expression 101進行測試)
到這邊你可能會發現一個問題:
如果我想查”50+”怎麼辦?
意即將”+”當作一般字元而非特殊字元來查找,
單純查”50+”、避免查成”50”或”500000000”。
此時我們便需要:
 : 稱為跳脫字元, 可去除特殊字元的功用、讓特殊字元回歸成普通字元。比如想
查”50+”, 得寫成”50+”避免上述情形發生。同理亦適用於. * ^ $ ?。
( ̄﹁ ̄) 有嗎啥問題
這樣就結束了! 耶!
…你想得太天真了。
d: 所有數字,等同[0-9]。d是數字(digit)的意思。
D: 數字以外的字元, 等同[^0-9]或[^d]。比如abcde,*()#%都符合。
l: 所有小寫字母, 等同[a-z]或abcdefghijklmnopqrstuvwxyz。l是小寫(lower)的意思。
L: 小寫字母以外的字元, 等同[^a-z]或[^l]。比如ABC, 123, *()#%都符合。
u:所有大寫字母, 等同[A-Z]或ABCDEFABCDEFGHIJKLMNOPQRSTUVWXYZ。u是大寫
(upper)的意思。
U:大寫字母以外的字元, 等同[^A-Z]或[^u]。比如abc, 123, *()#%都符合。
記完了特殊字元後,
讓我們來看看特殊字元的衍生──字元族(Character Class)。
我們已經知道了[A-Z]代表大寫字母A到Z;[a-z]代表小寫字母a到z;[0-9]代表阿拉伯數字0到9。
然而每次寫[a-z]相當麻煩又不直覺,因此正規表達式又內定了一些字元族:
w: 所有大小寫字母、數字與底線_ , 等同[A-Za-z0-9_]。比如"$5.28"可比對出”5”。
W: 大小寫字母、數字與底線_以外的字元, 等同[^A-Za-z0-9_]。比如"30%"可比對
出”%”。
a: 所有字母與數字, 不含底線。等同[A-Za-z0-9]。
c: 所有字母。等同[A-Za-z] 。
s: 所有空格。由於空格大小不一, s同時包括了空白鍵、tab、換頁、換行。若要更精
確── 代表空白鍵、t代表tab、f代表換頁(form-feed)、n代表換行。
S: 非空格字元, 等同[^s]。
z: 代表整數, 等同[0-9]+。z是整數集(zahlen)的意思。
1.只能輸入3位數字。
答: /^d{3}$/。
開頭必須是數字(^d)且有三次({3}),後面不能接其他字元($)。
2. 驗證手機號碼。
答: /^09[0-9]{8}$/。
開頭必須是(^09),加上8個任意數字([0-9]{8}),後面不能接其他字元($)。
3. 驗證身分證。
答: /^c[12]d{8}$/。
開頭必須是1個任意英文字母(^c),第二個字元必須是1或2([12]),加上8個任意數字
(d{8}),後面不能接其他字元($)。
小練習:(可使用Regular Expression 101進行測試)
艮! 到底結束了沒
恩…接下來還有很多 好啦我是說regex還有很多語法
但這次課程先教到這邊
最後來驗收一下~
還記得我們一開始提到的密碼驗證條件嗎
「密碼必須是包含大小寫字母和數字的組合,且長度在8-12之間」
/(?=.*u)(?=.*l)(?=.*d).{8,12}$/
.{8,12} : 表示字串長度須介於8~12之間。
?=.* : 字串的篩選條件。 比如(?!.*[d])表示字串中必須要有數字出
現。(?!.*[U])則代表字串中不能有大寫英文字母出現。
這邊需要幾個進階的正規表達式的符號來達成:
學會最後這兩招, 我們的任務就大功告成了!
/ ^ [A-Z] d{5} $ /gi
起始 結束
將式子包起來
所有數字
=[0-9]=u
大寫字母 字元數
比對方式(flag)
來總複習一次regex的標準格式吧!
> 正規表達式入門容易
> 從學會到精通卻是一段陡峭的學習曲線
> 身為正規表達初心學習者,還有很多待發掘的知識
> 歡迎大家日後一同討論精進、感受regex的魅力吧
結語
小智和皮卡丘打架後、盛怒之下寫了一封恐怖黑函寄給皮卡丘。
皮卡丘該怎麼過濾小智的惡意來信?
他只知道小智很愛罵: fuck you, 和智障、白癡與笨蛋。
因此信件可能會寫成 “Fuck U 智障”、”fuck you白癡”、”fUCK YoU 笨
蛋”、”FuckU白癡”等形式。
題外話: regex生活小應用
答: regex比對字串:/fucks*(yo)?us*智障|白癡|笨蛋/i

正規表達式_Regular Expression