什麼是正規表達式 Regular expressions
英文 Regular expressions 譯為常用表達,在中文的別名有稱為正則表達式、正規表示法、正規式等…
Regular expressions 是在 UNIX 中發展出的字串比對技巧,其基本概念用簡單(但強大)的符號來比對字串,並可對符合比對條件的字串進行修改或其他運算。
在軟體工程中,很多的地方都會透過正規表達式 (正則表達式) 來進行字串或字元的比對判斷,像是資料庫語法、後端程式語言、輸入指令核對塑等…
是一種用來描述字串符合某個語法規則的模型 (pattern),可用來文字的搜尋、比對、萃取、替代、轉換等等,在許多的程式語言中都支援正規表達式的使用。
在網頁前端開發上來說,以 JS 為主的自動化流程工具 (webpack or gulp) 、HTML 網頁前端輸入框輸入時直接回饋,也都能以這樣簡潔的方式來設計與運用。
例如:訂單規則 b1234567890 (B 開頭後十碼),類這樣的方式就正規表達式的規劃。
JavaScript 的 RegExp 規劃正規表達式
JavaScript 的正規式是一個內建的物件,其建構函數(Construction functoin)為 RegExp,兩個斜線 / / 或是 new RegExp() 來建立一個 RegExp 物件。
參數一:pattern﹙模型﹚ / 參數二:flag﹙標籤﹚
參數一:pattern﹙模型﹚的 literal 與 new RegExp() 建構函式物件寫法
在基本的撰寫上可只用一個參數的方式。
1 2 3 4 | // 1. 使用 literal 方式在 script 載入時就被編譯,效能較好。 const regex = /some text/; // 2. new 建構一個 RegExp 物件,適用在需要動態產生 pattern 的場合。 const regex = new RegExp('some text'); |
參數二:flag﹙標籤﹚配和字符做細部的批配方式
第二個參數 flag (標籤) 加上設定,能做更細部的批配方式。
– g:全域比對(Global match)
– i:忽略大小寫(Ignore case)
– gi:全域比對並忽略大小寫
1 2 | const regex = /some text/i; const regex = new RegExp('some text', 'g'); |
了解 JavaScript 的 new RegExp() 與 literal 二種正規表達式的方式,以下先透過 .test() 方法針對使用單一個參數展示用法。
1 2 3 4 5 6 7 8 | const regex_literal = /hello/; // 宣告正規表達式規則 regex_literal.test('hello'); // true regex_literal.test('hello123'); // true regex_literal.test('123hello123'); // true regex_literal.test('123hello'); // true regex_literal.test('Hello'); // false 如果英文單字前方使用 H 大寫,此時會回應錯誤 |
使用第二個參數 flag (標籤) 寫法,針對先前的驗証方式做出調整。
1 2 3 4 5 | const regex_literal_i = /hello/i; regex_literal_i.test('hello'); // true regex_literal_i.test('HelLo'); // true regex_literal_i.test('123HelLO'); // true |
RegExp 與 String 原型方式,使用正規式
g : global 的意思,找到之後會繼續往後配對。
1 2 3 | const regex_literal_g = /hello/g; regex_literal_g.test('hello'); // 輸入瀏覽器 console 時顯示是 true,但表達式回傳確是 false |
但很怪是在用 .test() 方法使用時,回應出來的結果確是不同,明明查驗的部份都是 hello,但確回傳的是 false,原來 .test() 方法所處理的對象是 RegExp,這部份就與 .exec() 一樣。
RegExp.prototype.test():搜尋字串中是否有符合的部分,回傳 true/ false。
RegExp.prototype.exec():以陣列回傳字串中匹配到的部分,否則回傳 null。
想要看字串是否包含某 pattern 時,使用 test 或 search;
想要更多的資訊(花較多耗效能),則使用 exec 或 match。
String.prototype.match():以陣列回傳字串中匹配到的部分,否則回傳 null。
String.prototype.replace():尋找字串中匹配的部分,並取代之。
String.prototype.search():尋找字串中是否有符合的部分,有的話回傳 index,否則回傳 -1。
String.prototype.split():在字串根據匹配到的項目拆成陣列。
在此, g 的用法指的是批配後會接著在處理,所以另外改用 .replace() 的字串處理方法進行查找後做更換的動作,這樣就可以了解到批配的原理,特別將字串只查找 ll。
1 2 3 4 5 | const regex_literal_g = /ll/g; 'hello'.replace(regex_literal_g, 'LL'); // "heLLo" 'hellohello'.replace(regex_literal_g, 'LL'); // "heLLoheLLo" 'hellllo'.replace(regex_literal_g, 'LL'); // "heLLLLo" |
character﹙特殊字元﹚
1 | const str ='This is a string'; |
^:pattern 必須在字串的開頭
1 2 | str.match(/^This/); // Array [ "This" ] str.match(/^THIS/); // null |
$:pattern 必須在字串的結尾
1 2 | str.match(/This$/); // null str.match(/string$/); // Array [ "string" ] |
|﹙or 或﹚:前後字串都比對
1 2 3 4 5 6 7 8 | const colorRE = /color|colour/; colorRE.test('color'); // true colorRE.test('colour'); // true colorRE.test('colours') ; // true colorRE.test('colors'); // true colorRE.test('colo'); // false colorRE.test('colou'); // false |
\﹙反斜線﹚:比對特殊符號跳脫特殊字元
比對特殊符號時,使用反斜線 \ 來跳脫特殊字元。
1 2 | const regex = /\$100/ regex.test('$100') // true |
.:任意一個字元前後批配 (類 PHP . 方式組字串)
針對單一個字元進行前後字元組合的批配。
1 2 3 4 5 6 7 8 9 | var a_before_regex = /a.man/; // a*man 都會 match,例如 "acman", "awman", 但 "a\nman" 無法匹配。 a_before_regex.test('acman'); // true a_before_regex.test('awman'); // true a_before_regex.test('a\nman'); // false var a_after_regex = /.a/; // 任何一個字元後加上 a a_after_regex.test("a"); // false a_after_regex.test("aa"); // true a_after_regex.test("1a"); // true |
[]:多個字元
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // 只要是英文大寫字母,就比對成功 const regex = /[ABCDEFGHIJKLMNOPQRSTUVWXYZ]/ 'K'.match(regex) // ["K", index: 0, ...] 'δ'.match(regex) // null // 可以使用 '-' 來簡化集合,'A-Z' 表示英文字母 A ~ Z 都符合 const regex = /[A-Z]/ // 小寫 a 或大寫 A var regex = /[aA]/; // 若要比對的是英文或數字,可以這樣表示 const regex = /[A-Za-z0-9]/ // 匹配所有不是 a 或 A 的字 var regex = /[^aA]/; |
集合有對應的特殊字元,可視為縮寫。
1 2 3 4 | const regex = /./ // 比對換行符號外的任意一個字元 const regex = /\d/ // 比對一個數字,相等於 /[0-9]/ const regex = /\w/ // 比對一個英文、數字或底線,相等於 /[A-Za-z0-9_]/ const regex = /\s/ // 比對一個的空格 (ex: space, tab, 換行, ...) |
使用 ^ 排除。
1 2 3 4 5 6 7 8 9 | const regex = /[^\w]/ regex.test('a') // false regex.test('!') // true /* 不是 a 都會 match */ var regex = /[^a]/; /* 不是數字都會 match */ var regex = /[^0-9]/; |
() ﹙括號﹚:套用到所有
1 2 | var regex = /^a|^the|^an/; // 套用到裡面所有的 var regex = /^(a|the|an)/; // 等同於 |
實例
身份證字號一個英文字母加九個數字組合
身份證字號的格式是由一個英文字母加上九個數字組合而成,要求使用者輸入身份證字號,以使用 JavaScript 的正規表示法來驗證其格式的正確性。
1 2 3 4 5 | <form> 身份證字號: <input type="text" value="A12345678" onBlur="checkID(this.value)" /> (第一個英文字母需大寫) </form> |
1 2 3 4 | function checkID(string) { re = /^[A-Z]\d{9}$/; if (!re.test(string)) alert('你的身份證號碼格式不對!'); } |
/^[A-Z]\d{9}$ 正規表達式說明如下。
- ^:代表字串開始位置。
- [A-Z]:代表由 A 至 Z 的所有可能英文字母
- \d:代表由 0 至 9 的數目字(事實上也可以寫成 [0-9])
- {9}:則代表需要有九個數目字。
- $:代表字串結束位置。
若不限大寫英文字母,只需將正規式改成 /^[a-zA-Z]\d{9}$/g 就可以了!
若不加入 ^ 和 $ 表達一個句子的開頭與結尾,那麼 /[A-Z]\d{9}/ 就會比對到其他不合法的身份證字號。
例如 AGF123456789 或是 F1234567890 等。
因此,加入 ^ 和 $ 可保證比對正確的字串,一定是由一個大寫英文字母加上九個數字所構成。
身分證號碼的驗證規則:
一般對身份字號的認知共有 10 位,位第一位為英文字母,第二個數字是男女生之分,男生為 1,女生為 2,接下來的一陀數字。
身份證字號後面八個數字不是隨便打,但前面七個可以隨便打,但是最後一位為檢查碼,必須經過之前一個字母與8個數字的組合計算後得出。
wiki 中華民國國民身分證
信用卡號碼
簡單的 JS 判斷
1 2 3 4 | const card_re = /^\d{4}-\d{4}-\d{4}-\d{4}$/; // 輸入字串 '1111-1111-1111-1111' card_re.test('1111-1111-1111-1111'); // true |
實際在網頁中,透過 onBlur 事件去觸發。
1 2 3 4 5 6 7 8 9 | <form> 信用卡號碼: <input type="text" value="xxxx-xxxx-xxxx-xxxx" onBlur="checkCreditCard(this.value)" /> (格式:xxxx-xxxx-xxxx-xxxx) </form> |
1 2 3 4 5 | function checkCreditCard(string) { re = /^\d{4}-\d{4}-\d{4}-\d{4}$/; if (!re.test(string)) alert('你的信用卡號碼不符合「xxxx-xxxx-xxxx-xxxx」的格式!'); } |
SCSS webpack 工具,處理不批配檔名開頭不為 _ ﹙下底線﹚,批配多種副檔名
在 webpack 透過 loader 的一段程式碼,例如 loader: 'sass-loader' 取用指定的 sass 與 scss 副檔名,透過 test: /\.(sass|scss)$/, 做為取用對象,這個原理也是正規表達式所處理的。
結合先前所了解操作方式,直接用程式碼來使用,在 SCSS 的使用上所拆分出去的模組或連結檔,多半會在檔名前面加上 _ 做為排除對象。
1 2 3 4 | const SCSS_re = /^(?!_).*.(\.sass|\.scss)$/ SCSS_re.test('aa.scss'); // true SCSS_re.test('_aa.scss'); // false SCSS_re.test('aa.sscss'); // false |
/^(?!_).*.(\.sass|\.scss)$/ 以下說明
– 前後 // 宣告為正規表達式。
– ^ 查驗內容的語句開頭、 $ 為結尾。
– (?!_) 做為開頭也就是檔名前的 _ 下底線,做為排除對象。
– .*. 整段語句的接續開頭之後的地方,直到結尾副檔名前。
– (\.sass|\.scss) 包含著內容對象,指定 sass 與 scss 做為對象,而 \.sass 來說是真接處理成 .scss 字串,讓正規表達式了解副檔名的判斷範圍,沒加上 \ 反邪線會連包著著的 .sscss 對判斷通過。
參考資料:正規表示式排除特定字串
參考資料
– 課程筆記-第四週:期中考:打造全端 (Full Stack) 網站架構﹙Node.js直播班-2022春季班﹚ > (關鍵字搜尋與篩選,透過 JS 的正規表達式 new RegExp() 轉成 mongoDB 使用的 /<過濾用字串>/ 格式,不是 JS 的字串格式所能實現)
– MDN:正規表達式、使用正則表達式校驗
– Regular Expression (regex),要成為GA專家一定要懂的正規表示式
– 五倍紅寶石:十五分鐘認識正規表達式,解決所有文字難題
– 保哥:使用 Regular Expression 驗證密碼複雜度
– 正規表示法:表單資料驗證 (說明在 JS Regular expressions 的概念與運作方式)
– pjchender – [JS] 正則表達式(Regular Expression, regex)
– 使用正規表示法分組 (比對 HTML 標籤與次數)
– IT人 – javascript常用的正規表示式
– 程式柴 CodeShiba – 【 初學者教學 】 一小時正規表達式教學 Regular Expression Tutorial (有包含直接在線上程式教學破關方式解題)