張智星 jang@mirlab.org http://mirlab.org/jang 台大資工系 多媒體檢索實驗室 第十章 通用表示法 張智星 jang@mirlab.org http://mirlab.org/jang 台大資工系 多媒體檢索實驗室
本章大綱 大綱 主題 本章介紹通用表示法,使用強大的字串比對方式,可以在進行 JavaScript 程式設計時,能夠有事半功倍的效果。 10-1:資料驗證 10-2:資料修改 10-3:通用式相關列表 10-4:常用資料規則
10-1:資料驗證 本小節介紹通用表示法及其用法。
基本介紹 「通用表示法」或「通用式」(Regular expressions)是在 UNIX 中發展出的字串比對技巧。 目標:用格式簡單、功能強大的符號來比對複雜的字串。 許多軟體或指令都支援通用表示法。 JavaScript 及 Vbscript:格式稍不同,但功能一樣 Unix 指令:如 grep、sed、awk、ed、vi、emacs 等。 MATLAB, Python, Perl, …
JavaScript 的通用式 通用式是一個內建的物件 用法 說明 建構函數(Construction functoin)為 RegExp。 pattern 是通用表示法的字串。 flag 是比對的方式: g:全域比對(Global match) i:忽略大小寫(Ignore case) gi:全域比對並忽略大小寫 re = new RegExp("pattern", "flag") re = /pattern/flag //上面的簡寫格式
範例10-1(1) 說明 主題:簡易身分證字號驗證 連結:regExpID01.htm (remote host, local host) 程式碼重點 說明 re=/^[A-Z]\d{9}$/ 就是一個通用式。 以re.test()比對字串string,回傳true代表比對正確,反之回傳false。 function checkID(string){ re = /^[A-Z]\d{9}$/; if (re.test(string)) alert("成功!符合「" + re + "」的格式!"); else alert("失敗!不符合「" + re + "」的格式!"); }
範例10-1(2) 通用表示法解釋: /^[A-Z]\d{9}$/ 比對數個字元中的任一個字元,可用「[]」,並可用「-」來代表字母或是數字的範圍。 [A-Z] 代表由 A 至 Z 的任一個英文字母。( 亦可寫成[ABCDEFGHIJKLMNOPQRSTUVWXYZ]) [a-zA-Z] 代表不限大小寫的一個英文字母 \d 代表0 至 9 的數字。 亦可寫成[0-9]或[0123456789] {9} 代表前一個字元的重複次數。 \d{9} 代表需要有九個數字 。 ^ 代表字串開始位置。 $ 代表字串結束位置。 若沒以上兩個符號,那麼只要任一個字串中間比對成功即可。
範例10-2 主題:簡易信用卡卡號驗證 連結: regExpCreditCardNumber01.htm (remote host, local host) 程式碼重點 說明 也可寫成: re = /^(\d{4}-){3}\d{4}$/ 重複的部分多於一個字母,必須將需要重複的部分放入小括號內,再由大括號包夾重複的次數。 re = /^\d{4}-\d{4}-\d{4}-\d{4}$/
範例10-3 主題:簡易英文名字驗證 連結: regExpEnglishName01.htm (remote host, local host) 程式碼重點 說明 [A-Za-z\-] :一個英文字母(可以大寫或小寫),或字元「-」 「-」:已經有特殊意義,必須在「-」之前加上「\」 「+」:重複前一個字元一次或多次 [A-Za-z\-]+ :英文字或「-」形成的字串,且長度至少為1 \s :空白字元,可以是空格、定位鍵、換列字元 re1 = /^[A-Za-z\-]+\s+[A-Za-z\-]+$/; re2 = /^[A-Za-z\-]+\s+[A-Za-z\-]+\s+[A-Za-z\-]+$/;
範例10-4 主題:簡易電子郵件格式驗證 連結: regExpEmail01.htm (remote host, local host) 程式碼重點 說明 「.」:比對任一個字元(不包含換列字元) 「.+」:長度不為零的字串 「\.」:「.」原先已具有特殊意義,必須加上反斜線 .{2,3} :長度為 2到3個字元 re = /^.+@.+\..{2,3}$/;
範例10-5 主題:電子郵件格式驗證(可避開含有空白的電子郵件帳號) 連結: regExpEmail02.htm (remote host, local host) 說明 \s :所有可能的空白字元,包含空白、定位鍵、換列字元等(不包含全形的空白) [^] :在中括弧內是代表「否定」 注意:^ 在一般通用表示法的意義是「字串開始的位置」,但放在中括弧內,則代表「否定」或「非」。 [^\s]+:一個或多個非空白字元所形成的字串 re = /^[^\s]+@[^\s]+\.[^\s]{2,3}$/;
範例10-5 (2) 主題:電子郵件格式驗證(可避開含有空白的電子郵件帳號) 若要對電郵進行更嚴苛的比對,上述通用式可以改成 其中 \w 代表一個數字、字母或底線,全等於 [a-zA-Z0-9_]。(但這樣嚴苛的標準也可能錯誤地阻擋正常的電郵。) re = /^\w+@\w+\.\w{2,3}$/;
範例10-6 主題:通用式的完整測試頁(列出比對到字串) 連結:regExpTest01.htm (remote host, local host) 程式碼重點 說明 使用了字串的 match() 方法,對通用式進行比對。 matched = str.match(regexp) 可將比對到的字串送到一個陣列,以便後續列出比對結果。 var matched = str.match(regexp); for (var i=0; i<matched.length; i++) dispstr = dispstr + "\n" + matched[i];
10-2:資料修改 本小節介紹如何使用通用表示法來進行字串字串的修改。
通用表示法的字串方法 用途 方法 強化搜尋比對 立即修改(修特別是改表單資料) 字串方法 功能 string.search(re) 通用式 re 在某個字串 string 出現的位置 string.match(re) 從字串 string 抽取符合通用式 re 的子字串,並以字串陣列傳回 string.replace(re, newStr) 將字串 string 符合通用式 re 的部分,代換為 newStr
範例10-7 主題:搜尋並列出位置(判斷第一個符合的位置) 連結:regExpSearch01.htm (remote host, local host) 程式碼重點 說明 str.search(re) 將會傳回符合 re 的第一個位置。(若沒找到則回傳-1) str.search(re) 只能用來搜尋某個通用式在一個字串的第一次出現的位置。 function regExpMatch(string, pattern, flag){ var regexp = new RegExp(pattern, flag); var index = string.search(regexp); alert(index); }
範例10-8 主題:搜尋並列出位置(取出符合的所有子字串) 連結:regExpMatch01.htm (remote host, local host) 程式碼重點 說明 使用string.match(regexp)可回傳符合的所有子字串。 傳回的 matched 變數是一個陣列,包含所比對到的字串。 function regExpMatch(string, pattern, flag){ var regexp = new RegExp(pattern, flag); var matched = string.match(regexp); alert(matched);}
範例10-9 主題:搜尋並代換 連結:regExpReplace01.htm (remote host, local host) 程式碼重點 說明 使用str.replace將符合通用式的第一部分替換成新字串。 欲將所有符合的替換成新字串,只要將選項改成「g」。 function regExpReplace(strId, pat1id, pat2id, flagId){ var regexp = new RegExp(pat1id.value, flagId.value); var str = strId.value; var newString = str.replace(regexp, pat2id.value); alert(newString);}
範例10-10 主題:修正中文姓名(去除表單前後空白) 連結: regExpReplace02.htm (remote host, local host) 程式碼重點 說明 [\s ] :英文空白字元或大五碼的全形空白。 replace(/[\s ]+/g, "") :將「 (/[\s ]+/g 」此類字串全部代換為空字串。 function checkChineseName(uiControl) { uiControl.value = uiControl.value.replace(/[\s ]+/g, ""); }
範例10-11 主題:修改英文姓名(消除前後空白並合併中間空白) 連結: regExpReplace03.htm (remote host, local host) 程式碼重點 說明 「|」可以代表「或」。 刪除頭尾字串兩式可合併: str = str.replace(/^[\s ]+|[\s ]+$/g, ""); str = str.replace(/^[\s ]+/g, ""); // 刪除頭部的空白字串 str = str.replace(/[\s ]+$/g, ""); // 刪除尾部的空白字串 str = str.replace(/[\s ]+/g, " "); // 將空白字串換成一半形空格
通用式的比對原則 貪心比對(Greedy Match) 最小比對(Minimum Match) 遇到重複字元時,「貪」到越多的字元越好。 必須在重複字元後面加上一個問號,代表「在可能比對成功的情況下,比對越少越好」。
範例10-12 主題:通用式的「貪心比對」與「最小比對」 連結: regExpGreedy01.htm (remote host, local host) 程式碼重點 說明 第一個通用式是採取預設的「貪心比對」,因此比對到的字串會是在比對成功的情況下最長的字串。 第二個通用式中,加了一個問號,採取「最小比對」,因此比對到的字串是在比對成功的情況下最短的字串。 re = /b.*t/; re = /b.*?t/;
範例10-13 主題:「越左越貪」比對方式 連結: regExpGreedy02.htm (remote host, local host) 程式碼重點 說明 通用式中加括號,代表符合比對條件者,將被設定至 RegExp.$1(簡寫成$1)、RegExp.$2 (簡寫成$2)等變數中。 使用「貪心比對」時,會採用「越左越貪」,若要推翻此原則,可適時使用問號,以採用「最小比對」。 第一個通用式採取預設的貪心比對,第二個通用式適時加入問號,因此結果不同。 re = /a(.*)b(.*)d/; re = /a(.*?)b(.*)d/;
範例10-14 主題:對調兩個英文字(replace的運用) 連結: regExpReplace04.htm (remote host, local host) 程式碼重點 說明 /(\w+)\s+(\w+)/:判斷兩單字位置。 replace(regexp, "$2 $1"):對調兩單字位置。 var regexp = /(\w+)\s+(\w+)/; var newString = id.innerHTML.replace(regexp, "$2 $1");
範例10-15 主題:表單資料的修正與驗證 連結: regExpReplace05.htm (remote host, local host) 說明 利用 replace() 在 onBlur 事件時,先修正文字欄位,再進行驗證。 onBlur 事件後,JavaScript 會以通用式對表單元素的值進行修正與驗證。
10-3:通用式相關列表 本小節列出常用的方法與通用式字元介紹。
通用式方法列表 通用式相關的方法 功能 re.exec(string) 從字串 string 抽取符合通用式 re 的子字串,並以字串陣列傳回 re.test(string) 以字串 string 比對通用式 re,並傳回比對結果(true 代表比對成功,false 代表比對失敗) string.search(re) 通用式 re 在某個字串 string 出現的位置 string.match(re) 從字串 string 抽取符合通用式 re 的子字串,並以字串陣列傳回,此功能和 re.exec(string) 相同 string.replace(re, newStr) 將字串 string 符合通用式 re 的部分,代換為 newStr
通用式的應用(1) 通用式 說明及範例 比對不成立之字串 /a/ 含字母 "a" 的字串,例如 "ab", "bac", "cba" "xyz" /a./ 含字母 "a" 以及其後任一個字元的字串,例如 "ab", "bac"(若要比對.,請使用 \.) "a", "ba" /^xy/ 以 "xy" 開始的字串,例如 "xyz", "xyab"(若要比對 ^,請使用 \^) "axy", "bxy" /xy$/ 以 "xy" 結尾的字串,例如 "axy", "abxy"(若要比對 $,請使用 \$) "xya", "xyb" /[13579]/ 包含 "1" 或 "3" 或 "5" 或 "7" 或 "9" 的字串,例如:"a3b", "1xy" "y2k" /[0-9]/ 含數字之字串 不含數字之字串 /[a-z0-9]/ 含數字或小寫字母之字串 不含數字及小寫字母之字串
通用式的應用(2) 說明: 「/^/」代表一個字串的開始位置,同理「/$/」代表一個字串的結束位置,但如果「 [^]」 就代表「否定」。 在字元前加上 「\」,可避掉特殊字元的特殊意義。 通用式 說明及範例 比對不成立之字串 /[a-zA-Z0-9]/ 含數字或字母之字串 不含數字及字母之字串 /b[aeiou]t/ "bat", "bet", "bit", "bot", "but" "bxt", "bzt" /[^0-9]/ 含非數字之字串,例如"25f6" (若要比對 ^,請使用 \^) 只含數字之字串 /[^aeiouAEIOU]/ 含非母音之字串,例如“abeu" 只含母音之字串 /[^\^]/ 含非 "^" 之字串,例如 "xyz", “^b^" "^^^^"
通用式的特定字元 通用表示法的特定字元 說明 等效的通用表示法 \d 數字 [0-9] \D 非數字 [^0-9] \w 數字、字母、底線 [a-zA-Z0-9_] \W 非 \w [^a-zA-Z0-9_] \s 空白字元 [ \r\t\n\f] \S 非空白字元 [^ \r\t\n\f] 說明 RegExp(pattern, flag) 的方式建立通用式物件時,若 pattern 包含以反斜線開頭的特殊字元(例如 \d、\w、\s 等)時,必須加上一個反斜線。 例:re = new RegExp("\\d+\\s\\w+", "g");
定義字元的重複次數 通用表示法 說明 /a?/ 零或一個 a(若要比對? 字元,請使用 \?) /a+/ /a.{5}b/ a 和 b中間夾五個(非換行)字元
通用式總列表(1) 字元 說明 簡單範例 \ 避開特殊字元 /A\*/ 可用於比對 "A*",其中 * 是一個特殊字元,為避開其特殊意義,所以必須加上 "\" ^ 比對輸入列的起始位置 /^A/ 可比對 "Abcd" 中的 "A",但不可比對 "aAb" $ 比對輸入列的結束位置 /A$/ 可比對 "bcdA" 中的 "A",但不可比對 "aAb" * 比對前一個字元零次或更多次 /bo*/ 可比對 "Good boook" 中的 "booo",亦可比對 "Good bk" 中的 "b" + 比對前一個字元一次或更多次,等效於 {1,} /a+/ 可比對 "caaandy" 中的 "aaa",但不可比對 "cndy" ? 比對前一個字元零次或一次 /e?l/ 可比對 "angel" 中的 "el",也可以比對 "angle" 中的 "l" . 比對任何一個字元(但換行符號不算) /.n/ 可比對 "nay, an apple is on the tree" 中的 "an" 和 "on",但不可比對 "nay"
通用式總列表(2) 字元 說明 簡單範例 (x) 比對 x 並將符合的部分存入一個變數 /(a*) and (b*)/ 可比對 "aaa and bb" 中的 "aaa" 和 "bb",並將這兩個比對得到的字串設定至變數 RegExp.$1 和 RegExp.$2。 x|y 比對 x 或 y /a+|b+/g 比對 "aaa k bb" 中 "aaa" 和 "bb" {n} 比對前一個字元 n 次,n 為一個正整數 /a{3}/ 可比對 "lllaaalaa" 其中的 "aaa",但不可比對 "aa" {n,} 比對前一個字元至少 n 次,n 為一個正整數 /a{3,}/ 可比對 "aa aaa aaaa" 其中的 "aaa" 及 "aaaa",但不可比對 "aa" {n,m} 比對前一個字元至少 n 次,至多 m 次,m、n 均為正整數 /a{3,4}/ 可比對 "aa aaa aaaa aaaaa" 其中的 "aaa" 及 "aaaa",但不可比對 "aa" 及 "aaaaa" [xyz] 比對中括弧內任一字元 /[ecm]/ 比對 "welcome" 中"e" 或 "c" 或 "m" [^xyz] 比對不在中括弧內出現的任一個字元 /[^ecm]/ 可比對 "welcome" 中的 "w"、"l"、"o",可見出其與 [xyz] 功能相反。(同時請同學也注意 /^/ 與 [^] 之間功能的不同。)
通用式總列表(3) 字元 說明 簡單範例 [\b] 比對退位字元(Backspace character) 可以比對一個 backspace ,也請注意 [\b] 與 \b 之間的差別 \b 比對英文字的邊界,例如空格 /\bn\w/ 可以比對 "noonday"中 'no' ; /\wy\b/ 可比對 "possibly yesterday." 中 'ly' \B 比對非「英文字的邊界」 /\w\Bn/ 可以比對 "noonday" 中'on' , 另外 /y\B\w/ 可以比對 "possibly yesterday." 中的 'ye' \cX 比對控制字元,X 是控制字元 /\cM/ 可比對 一個字串中的 control-M \d 比對任一個數字,等效於 [0-9] /[\d]/ 可比對 由 "0" 至 "9" 的任一數字 但其餘如字母等就不可比對 \D 比對任一個非數字,等於 [^0-9] /[\D]/ 可比對 "w" "a"... 但不可比對如 "7" "1" 等數字 \f 比對 form-feed 若是在文字中有發生 "換頁" 的行為 則可以比對成功
通用式總列表(4) 字元 說明 簡單範例 \n 比對換行符號 若是在文字中有發生 "換行" 的行為 則可以比對成功 \r 比對 carriage return \s 比對任一個空白字元(White space character),等效於 [ \f\n\r\t\v] /\s\w*/ 可比對 "A b" 中的 "b" \S 比對任一個非空白字元,等效於 [^ \f\n\r\t\v] /\S\w*/ 可比對 "A b" 中的 "A" \t 比對定位字元(Tab) \v 比對垂直定位字元(Vertical tab) \w 比對數字字母字元(Alphanumerical characters)或底線字母("_"),等效於 [A-Za-z0-9_] /\w/ 可比對 ".A _!9" 中的 "A"、"_"、"9"。
通用式總列表(5) 字元 說明 簡單範例 \W 比對非「數字字母字元或底線字母」,等效於 [^A-Za-z0-9_] /\W/ 可比對 ".A _!9" 中的 "."、" "、"!",可見其功能與 /\w/ 恰好相反。 \ooctal 比對八進位,其中octal是八進位數目 /\o123/ 可比對 與 八進位的ASCII中 "123" 所相對應的字元值。 \xhex 比對十六進位,其中hex是十六進位數目 /\x38/ 可比對 與 16進位的ASCII中 "38" 所相對應的字元。
10-4:常用資料規則 本小節介紹日常生活中常用的資料規則。
身分證字號的檢查碼(1) 基本認知 共有10位 第一位為英文字母 第二個數字男生為 1,女生為 2 最後一位為檢查碼,經過之前一個字母與 8 個數字的組合計算後得出。
身分證字號的檢查碼(2) 計算方法 英文代號轉換成數字(代表出生時的戶籍所在地) 英文轉成的數字,個位數乘9再加上十位數 各數字從右到左依次乘1、2、3、4...8 求出(2)、(3)之和 求出(4)除10後之餘數,用10減該餘數,結果就是檢查碼,若餘數為0,檢查碼就是 0。
身分證字號的檢查碼(3) 英文代號以下表轉換成數字(代表出生時的戶籍所在地): A=10 台北市 J=18 新竹縣 S=26 高雄縣 B=11 台中市 K=19 苗栗縣 T=27 屏東縣 C=12 基隆市 L=20 台中縣 U=28 花蓮縣 D=13 台南市 M=21 南投縣 V=29 台東縣 E=14 高雄市 N=22 彰化縣 W=32 金門縣 F=15 台北縣 O=35 新竹市 X=30 澎湖縣 G=16 宜蘭縣 P=23 雲林縣 Y=31 陽明山 H=17 桃園縣 Q=24 嘉義縣 Z=33 連江縣 I=34 嘉義市 R=25 台南縣
身分證字號的檢查碼(4) 範例 例如: 身分證號碼是 W100232754 W 1 0 0 2 3 2 7 5 3 2 W 1 0 0 2 3 2 7 5 3 2 X X X X X X X X X X 1 9 8 7 6 5 4 3 2 1 ─────────────────── 3 +18 +8 + 0 + 0 + 10 +12 +6 +14 + 5 =76 76/10=7....6 (餘數) 10-6=4 (檢查碼)
第一碼為 1,且前四碼為 1800。 第一碼為 2,且前四碼為 2131。 第一碼為 3,且前三碼介於 300和399之間。 信用卡卡片編碼(1) 不同卡別編碼規則 信用卡號的最後一個數字就是信用卡的檢查碼。 卡別 位數 規則 Visa Card 16 第一碼為 4。 Master Card 第一碼為 5,且前二碼介於 51 和 55 中間。 American Express 15 第一碼為 3,且前三碼介於 340 和 379 之間。 JCB Card 15 15 16 第一碼為 1,且前四碼為 1800。 第一碼為 2,且前四碼為 2131。 第一碼為 3,且前三碼介於 300和399之間。
信用卡卡片編碼(2) 計算方法 將信用卡的每個數字設定權重:從右向左,檢查碼除外,每個數字的權重分別是 2、1、2、1、2、1 ...。(若信用卡共有16碼,那麼最左邊數字的權重是 2;若信用卡卡號共有15碼,那麼最左邊數字的權重就是 1。) 將每個數字乘上權重,所得的加權數字若大於 9,那麼就從這加權數字裡扣除 9。 將所有處理過的加權數字全部加總起來,並且除以 10,取其餘數。 若餘數是 0,檢查碼就是 0,否則檢查碼就等於 10 減掉此餘數所得的值。
信用卡卡片編碼(3) 範例1 若某張 Visa 信用卡卡號是 4311-4656-0640-6131,則其計算過程如下: 卡號 4 3 1 1.權重 2 x 2.加權數字 8 10 1 12 3 3.計算總和 59 4.計算檢查碼 59 除以 10 的餘數是 9,所以檢查碼是 10 - 9 = 1。
信用卡卡片編碼(4) 範例2 美國運通卡(American Express),卡號是 3728 024906 54257(只有 15 碼),其計算過程如下: 卡號 3 7 2 8 4 9 6 5 1. 權重 1 x 2. 加權數字 14 5 16 7 18 9 12 3 10 1 3. 計算總和 53 4. 計算檢查碼 53 除以 10 的餘數是 3,所以檢查碼是 10 - 3 = 7。