Regular Expression - 正規表示式


正規語法 (Regular Grammar) 是一種相當簡單的語法,這種語法被 Perl 語言成功的用於字串比對,接著成為重要的程式設計工具。此種標準的正規語法後來被稱為正則表達式 (Regular Expression)。目前,大部分的語言都已納入正則表達式的函式庫,正則表達是可以說是程式設計師必定要瞭解的工具,也就是常識的一部分。


先看個簡單的例子

//RegExp是 Regular Expression的縮寫
//這句正規表示式要求輸入的資料只能是0~9的其中一個字元
var pattern = new RegExp("^[0-9]$");

console.log( pattern.test("0") ); //true
console.log( pattern.test("a") ); //false
console.log( pattern.test("12") ); //false

先不用了解程式碼的細節,稍微對正規表示式有個簡單的概念就好,我們進一步了解這奇奇怪怪的正規表示式到底該怎麼制定。


定義規則算式

規則算式常值是(regular expression literals)由一連串寫在兩個斜線字元(/)之間的字元所組成,譬如:/javascript/,夾在兩個斜線中間的部分,我們稱為pattern。把規則算式常值指定給變數後,該變數就成為一個規則算式物件。譬如:

var regexp = /[jJ]avaScript/;

有時候會在/pattern/後加上另一個符號,我們稱作attributes(修飾符),組起來就變成/pattern/attributes,譬如:

var regexp = /[0-9]/g;

以下是attributes的參考資料,先不用認真看,等等要用到再回頭查就好

修飾符(attributes) 描述
i 執行對大小寫不敏感的匹配。
g 執行全局匹配(查找所有匹配而非在找到第一個匹配後停止)。
m 執行多行匹配。

到這邊大家應該還是很模糊吧!沒關係,我們實際做一些簡單的練習,


驗證手機號碼

手機號碼是09開頭,後面接8個數字,不多不少,像是0912345678,所以想要驗證一筆資料是不是手機號碼,所要撰寫的程式碼如下:

    var pattern = /^09[0-9]{8}$/;
    var str = "0912345678";
    var result = str.match(pattern);
    console.log(result);
    //輸出結果:[ "0912345678" , index: 0, input: "0912345678" ]
    //            ↑符合規定的字串                   ↑原本的字串

第一步要撰寫正規表示式,我們用到的符號如下

形式 代表的字元集合
^ 定於字串首的錨點。在多行模式下,則是定於行首的錨點。
$ 定於字串尾的錨點。在多行模式下,則是定於行尾的錨點。
[...] 方括號中列出之字元的集合。我們可以用「首字元-尾字元」的簡寫式來定義一段連續字元,譬如:[A-Z] 是 26 個大寫英文字母的集合、[0-9] 是 10 個阿拉伯數字的集合。
{n} 前一項正好重複 n 次

說明/^09[0-9]{8}$/的由來:

  1. 09是固定的,所以我們直接打上去/09/
  2. 後面的要接的是0~9隨意一個數字,所以我們要打[0-9][]只代表一個字元,如果寫[0-9a-zA-Z]則代表這個字元可以是數字或字母,變成/09[0-9]/
  3. 但這只代表一個字元,要重複8次才行,所以緊接著加上{8},會變成/09[0-9]{8}/
  4. 頭要加上^,尾巴則加上$/^09[0-9]{8}$/

寫好正規表示式後,開始比對,使用match函式,match函式是會回傳符合正規表示式的字串,沒有符合的話會回傳null,符合的話則回傳一個物件,格式如上面程式碼註解所寫的樣子。

還有哪些函式可以用:

  • String型態中可使用正規表示式的函式
    • match - 回傳符合規定的資料區塊
    • replace - 將符合規定的資料區塊更換成別的字串,回傳取代後的字串
    • search - 尋找資料中有沒有符合規定資料區塊,回傳index
    • split - 將符合規定的資料區塊當作切割字串的依據,回傳陣列

練習

如何比對手機號碼的程式我們已經寫好了,可以驗證的格式如0912345678,但如果想要驗證的格式是0912-345-678,那正規表示式又該怎麼寫呢?這次練習,我們用\d來取代[0-9]


還有很多的符號要學,可以參考教學網站

一次只指定一個字元不過癮,也可以用Greedy quantifiers來指定字元可能出現的次數:

形式 意義
X? X出現一次或完全沒有
X* X出現零次或多次
X+ X出現一次或多次
X{n} X出現n次
X{n,} X出現至少n次
X{n,m} X出現至少n次,但不超過m次

一些常用的範圍,我們可以使用預先定義的字元類別:

形式 意義
. 符合任一字元
\d 等於 [0-9] 數字
\D 等於 [^0-9] 非數字
\s 等於 [ \t\n\x0B\f\r] 空白字元
\S 等於 [^ \t\n\x0B\f\r] 非空白字元
\w 等於 [a-zA-Z_0-9] 數字或是英文字
\W 等於 [^a-zA-Z_0-9] 非數字與英文字

選擇、群組、與參照(因為 | 會有問題,所以以下表格 | 用 l 代替)

形式 意義
xly x和y中,兩者擇其一,如 /aalbb/ 表示 aa 或 bb
(...) 把括號中的項目視為一個單元,同時把符合括號內規則的子字串存在參照(reference)中。
\n n是一個 1 到 99 的整數。用來表示第n個參照,其中存放符合第n個群組的子字串(第n個左括號所建立的群組)

滿滿的範例,看著看著就學會正規表示式了

規則算式 相符的字串
/a{1,3}/ a, aa, aaa, aaaa, baab
/ab{3,}/ abbb, abbbb, babbba, abbbbbbbbb
/[_A-Za-z]\w*/ JavaScript 合法的識別字名稱
/[A-VXYa-vxy]\d{9}/ 身份證字號:英文字母(W 和 Z 除外)後跟 9 個阿拉伯數字
/\d+/ 不帶正負號的整數,如:8, 26, 123, 7823 等等
/[+-]?\d+/ 帶或不帶正負號的整數,如:8, +26, -123, 7823 等等
/[+-]?\d*.?\d*/ 帶或不帶正負號的整數或小數,如:8, -15, +26.3, -123.0, 78.23 等等。註:由於 . 是一個特殊字元,所以在左邊的式中必須在其前加反斜線。
規則算式 相符的字串
/ab l cd l ef/ ab, cd, 或 ef
/0(2 l 4)\d{8}/ 台北或台中地區的電話號碼,如: 0212345678 或 0426328001
/(\d+).\1/ 小數點前後數字相同的字串,如:1.1, 123.123, 或 011.011
/(\d+)([a-z]+)\2\1/ 12abab12, 34aa34
/(\d+([a-z]+))\2\1/ 12abab12ab, 34aa34a
/(?:a+)(?:b+)(\d{3})\1/ ab123123, aaaabb135135

抓取一大段文字中需要的部分

從一大段文字中抽出你要的資訊,以下範例就是抽出email跟電話號碼。

var word = "[email protected] (555) 555-5555 111-222-3333 555 555-5551 [email protected] [email protected]",
    regexmail = /([\w\-][email protected][\w\.]+)/g,
    regexphone = /\(?\d{3}\)?[\s\-]\d{3}[\-\s]\d{4}/g;

document.write(word.match(regexmail) + '<br>' + word.match(regexphone));

email: ([\w-][email protected][\w.]+)

[\w-]→ 抓任何單一字元跟- // h,a,n,n,a,h
[\w-]+→ 抓成字串 // hannah
([\w-][email protected][\w.]+)→ 把email整個包起來抓

phone: \(?\d{3}\)?[\s-]\d{3}[-\s]\d{4}

\d{3}→ 3個數字 // 111
\(?\d{3}\)? → 3個數字可以被()包起來也可以不要 // 111 or (111)
\(?\d{3}\)?[\s-] → 3個數字後可能會是-或空格隔開 // 111-, 111
\(?\d{3}\)?[\s-]\d{3}→再接3個數字 // 111-222
\(?\d{3}\)?[\s-]\d{3}[-\s]→後面可能會是-或空格隔開 // 111-222-, 111-222
\(?\d{3}\)?[\s-]\d{3}[-\s]\d{4}→ 最後再接4個數字 // 111-222-3333

參考資料


註冊時的密碼驗證

如果要驗證一段密碼是不是符合下列條件

  1. 至少有一個數字
  2. 至少有一個小寫英文字母
  3. 至少有一個大寫英文字母
  4. 字串長度在 6 ~ 30 個字母之間

表示式應該寫

^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,30}$

參考資料:使用 Regular Expression 驗證密碼複雜度


驗證Youtube網址


練習

practice.html撰寫驗證程式碼

  • 驗證身分證字號,開頭大寫,第二個字元不是1就是2,如:A123456789
  • 驗證英文名字,大寫開頭,後面小寫,如:Allen,Mary
  • 輸入時間,如24:00,8:45

    電話區碼小知識
    身分證字號小知識

    1. 第一個英文字碼代表縣市簡碼,出生報戶口時的戶籍地
    2. 第二個數字第一碼代表性別,1代表男性,2代表女性
    3. 第三個字元到第九個字元為流水號碼,按鄉鎮市區及村里別與申報順序配賦
    4. 第十個字元為檢查號碼

  • RegExp
    • exec - 回傳符合規定的資料區塊,只回傳第一個符合的
    • test - 驗證資料符不符合規定,回傳true或false

new RegExp(pattern, attributes);

var re = new RegExp("abc"); //RegExp型態,可用exec,test

參考資料:

results matching ""

    No results matching ""