Boison
百日轉職前端工程師:第十三週正規表達式 《DAY 21》

大家好,這是百日轉職前端工程師的 Day21,也是 11/18(三),今天要來聊聊滿常見的正規表達式(Regular Expression) ,這是一個新手看到會昏頭看起來很像亂碼的工具,但是實際接觸後發現沒有那麼難,於是簡單來整理一下其用法,簡單來說正規表達式是被用來匹配字串中字元組合的模式,實際上其應用廣泛,從文本資料分析查詢到人工智慧的腳本編寫,都能看到正規表達式的使用。


一、什麼是正規表達式?

事實上正規表達式並不是程式語言,只是一款「表達字串形式」的「邏輯式」,1956 年由數學家 Stephen Kleene 所提出,包括 JavaScript, Perl, Python, Java, C/C++ 在內的多種程式語言都能支援正規表達式。

正規表達式乃身為一個程式工程師所具備的基本常識,其在上述語言中都能跑得動,只要學會正規表達式、就能跨平台使用且十年以上不退流行。

比方說當你要在一文本中查詢單字,但忘記信封是拼做 envelope ,還是 envlope 時,你可以用 enve?lope 去查詢,當你忘記灰色是 grey 還是 gray 時,你可以用 gr[ae]y 去查詢,而當你同時想查詢 wow、woow 跟 wooow 時,你可以寫成 wo+w,聽起來很方便他可以短短一行就取代一個迴圈,但他也有以下缺點:

  • 易讀性差:讀起來很困難,甚至連你自己都忘了在寫啥。
  • 維護性差:很難去修改微調應用不同情境。

所以通常會用在一些不會重複需要使用的小地方,而不會把大的、核心的專案部分用正規表達式來處理。


二、正規表達式的使用情境

以下三種情境都能透過正規表達式處理,快速的解決。

情境 1:尋找資料

尋找資料庫中某個資料,但可能以些微差異儲存,例如要找蘋果的英文單詞,但資料庫中有 apple 也有 Apple,甚至有人手誤的打成 applo。

情境 2:驗證資料

比方說在註冊需要填寫生日,但有人寫成 1991-07-20 、有人寫成 19910720,也有人寫成 1991/07/20 但這三種寫法我驗證後都要讓其通過的話。

情境 3:抽取資料

比方說我有以下五筆資料,但我只想抽取信箱網域(gmail、yahoo…)名稱。
aaa@gmail.com
ccc@gmail.com
ddd@yahoo.com.tw
eee@msn.com
fff@ptt.com

三、正規表達式的寫法

可以在這個網站  RegEx101 提供你的 RE 以及要比對的字串,試試看你的正規表達式寫法是否正確抓到你想要的資料。

1. 正規表達式基本寫法


你可以用 你可以用 /ant/ 去找出一個字串有沒有包含 ant,還有 ant 出現在哪個位置,如果你想要找出所有含 a 和 n 和 t 的字串,則可以用 /[ant]/ 去表示,那如果你想要去看是否有包含「數字」和「英文字」 ,你當然可以全部寫出來,但有更簡便的寫法如:/[0-9]/ 跟 /[a-z]/,若是要找大寫的英文字母呢? /[A-Z]/ 且可以合併使用,比方說你要找含有大小寫英文字母和數字要怎麼寫?/[0-9a-zA-Z]/ 即可,是不是很方便呀。

但以下提供再更簡化的寫法:

/\d/ = /[0-9]/
/\d\d\d/ (查三個連續的數字)
/\w/ = /[a-zA-Z0-9_]/ (「查大小寫數字和底線」)
/./ (查任意一個字元)

P.S 特別注意在程式碼中字串中要把 \d 改成 \\d,不然的話會被當作跳脫字元來看待。

但是你用上述的方法會查到所有「包含」上述字元條件的字串,如果你想要查開頭或者結尾包含呢?

/^xyz/ (查開頭包含 xyz 的字串)
/abc$/(查結尾包含 abc 的字串)
/^0988d\d\d\d\d\d$/(查開頭是 0988 的八位手機號碼)

如過是要找重複的連續字元可以再簡化如下:

/^0988\/ = /^0988\d{4}$/
/^0988\d{4,}$/ (查開頭是 0988 後面重複 4 次以上的連續數字)
/^0988\d{4,7}$/ (查開頭是 0988 後面重複 4~7 次的連續數字)
/^0988\d+$/ (查開頭是 0988 後面是不固定次數的連續數字)

2. 正規表達式實際用法

實際使用上一個例子是要定義三組變數:(1).你要尋找的字元,(2).被搜尋的字串,(3).匹配的結果。

var re = /李.明/
var str = ‘李曉明王阿明王小明李大明太大明阿明無名小站’
var result = str.match(re)
console.log(result)
/*
輸出:
0: “李曉明”
groups: undefined
index: 0
input: “李曉明王阿明王小明李大明太大明阿明無名小站”
*/

引用自 簡易 Regular Expression 入門指南

若是要找全部出現的字元的話,要在 // 後面加一個 g(golobal)如 /李.名/g ,並且使用 str.matchAll(re)。

最後再介紹一個很厲害的工具 Capturing Groups (),加在正規表達式中可以幫助你抓出專有名詞,實際前面曾經出現過的信箱網域名稱問題。

var emails = [
‘aaa@gmail.com’,
‘ccc@gmail.com’,
‘ddd@yahoo.com.tw’,
‘eee@msn.com’,
‘fff@ptt.com’
]
var re = /^.+@(.+?)\./
for(let email of emails) {
var result = email.match(re)
console.log(result[1])
}
/*
gmail
gmail
yahoo
msn
ptt
*/

引用自 簡易 Regular Expression 入門指南

拆解一下上述的匹配式如下

  • ^.+@
    • 是代表開頭是數字或者大小寫英文字母,連續 N 次接一個 @
  • (.+?)
    • 抓出數字或者大小寫英文字母任意個英文字母,? 代表捉出匹配的字元越少越好
  • ^.+@(.+?)\.
    • 則是抓出 ^.+@(.+?)\ 這串的「專有名詞」,匹配最後接上一個大小寫英文字母任意個英文字母。特別注意在字串中要把 . 改成 \. 否則會被當跳脫字元。

四、總結

以上大概用最簡單的方式介紹了正規表達式(Regular Expression)的概念,但要完整瞭解所有用法請參考以下本文之參考延伸資料。

註:
主要資料來源 1:胡立 – 簡易 Regular Expression 入門指南
參考延伸資料 2:[Javascript] 初探Regex 正規表達式
參考延伸資料 3:寫點科普 – 文本分析基礎-正規表達式(RegExp)
參考延伸資料 4:Regular Expressions for Regular Folk



作者介紹 - Boison

Boison

台大 MBA 畢業的筆記術達人,在臉書上經營近 5,000 人的閱讀社群「書旅」,平日熱愛將職場所學做筆記分享商業精華,因此又有「筆記狂 Boison」之稱, 歡迎你追蹤我的臉書發落第一手消息:「 Boison 臉書」;出版社正式合作可透過 dragoncres@gmail.com 聯絡。

發表迴響