「通用表示法」或「通用式」(Regular expressions)是在 UNIX 世界中發展出來的字串比對技巧,其基本概念是用一套格式簡單、但功能強大的符號來比對複雜的字串,並可對符合比對條件的字串進行修改或其他運算。事實上,UNIX 的許多軟體或指令都支援通用表示法,例如 grep、sed、awk、ed、vi、emacs 等。(但是這些東西大概只有像我這樣的 LKK 才會用吧。)
目前各個主流瀏覽器都支援 JavaScript 的通用表示法,特別適用於表單資料的驗證與修改。事實上,JavaScript 的通用表示法和 Perl 以及其他 UNIX 相關指令幾乎一模一樣,因此,在本章學到的通用表示法,也可以完全適用於 Perl 或 UNIX 相關指令。(一魚兩吃,真是太棒了!)
JavaScript 的通用式是一個內建的物件,其建構函數(Construction functoin)為 RegExp,典型用法如下:
re = new RegExp("pattern", "flag")
上述用法也可以簡寫成下列格式:
re = /pattern/flag
其中,pattern 是通用表示法的字串,flag 則是比對的方式。flag 的值可能有三種,分別解釋如下:
- g:全域比對(Global match)
- i:忽略大小寫(Ignore case)
- gi:全域比對並忽略大小寫
舉例來說,我們的身份證字號的基本格式,是由一個英文字母加上九個數字組合而成,如果我們要求使用者輸入身份證字號,就可以使用 JavaScript 的通用表示法來驗證其格式的正確性。例如,我們可用下列表單來要求使用者輸入身份證字號:
在上例中,我們只要按下「驗證」的按鈕,就會呼叫 checkID() 函數來對文字欄位中的身份證字號進行驗證。相關原始碼如下:
在上述範例中,/^[A-Z]\d{9}$/ 就是一個通用式,說明如下:
- 若要比對數個字元中的任一個字元,可用中括號,並可用「-」來代表字母或是數字的範圍,因此 [A-Z] 代表由 A 至 Z 的任一個英文字母。(若不嫌煩,當然也可以寫成 [ABCDEFGHIJKLMNOPQRSTUVWXYZ]。)
- \d 代表由 0 至 9 的數目字,事實上也可以寫成 [0-9] 或 [0123456789]。
- {9} 代表前一個字元的重複次數,因此 \d{9} 代表需要有九個數目字。
- ^ 代表字串開始位置,$ 代表字串結束位置。(若沒有這兩個符號,那麼只要任一個字串中間含有身份證字號,也可以比對成功。)
由上述說明,可知 /^[A-Z]\d{9}$/ 就代表可以比對身份證字號的通用式。此外,idNumber.value 代表使用者輸入的字串,re.test(string) 則是通用式 re 的一個方法,會傳回 true 或 false,代表比對是否成功。若要不限定是大寫英文字母,只需將上述範例的通用式改成 /^[a-zA-Z]\d{9}$/ 就可以了!
事實上,身份證字號本身就有內在的編碼規則,這些規則和使用者的性別有關,因此若要實現完整的表單驗證,就必須應用完整的身份證編碼規則,讀者可參考本章的最後一節。
另一個簡單的例子,是要求使用者輸入信用卡號碼,這是一組 16 個數字的號碼,例如:
當我們按下「驗證」按鈕時,JavaScript 會呼叫函數 checkCreditCard( ) 來對填入的資料進行驗證。相關原始碼如下:
在上例中,很顯然地,/^\d{4}-\d{4}-\d{4}-\d{4}$/ 就代表正確的信用卡格式。很明顯的,使用通用式會讓程式碼簡潔很多,而且會大大提高程式碼的正確性。(請和前面章節的類似範例 formValidation02.htm 比較看看。)但要注意的是,信用卡卡號本身就有內在的較複雜編碼規則,因此若要實現完整的表單驗證,就必須應用完整的信用卡卡號編碼規則,讀者可參考本章的最後一節。
如果重複的部分多於一個字母,我們就必須將需要重複的部分放在小括號內,再加上由大括號包夾的重複次數,例如,上述範例的通用式 /^\d{4}-\d{4}-\d{4}-\d{4}$/,也可以寫成 /^(\d{4}-){3}\d{4}$/,請試試看!
下一個例子,則是用通用表示法來驗證使用者的英文名字,例如:
當我們按下「驗證」按鈕時,JavaScript 會呼叫函數 checkEnglishName( ) 來對填入的資料進行驗證。相關原始碼如下:
對於上述範例程式,我們說明如下:
- [A-Za-z\-] 代表一個英文字母(可以大寫或小寫),或是字元「-」。特別要注意的是,由於「-」在中括號內部已經有特殊意義,若要避掉此特殊意義,就必須在「-」之前加上反斜線(「\」)。
- 加號代表重複前一個字元一次或多次,因此 [A-Za-z\-]+ 就代表由英文字母或是減號所形成的字串,且其長度至少是一。
- \s 代表空白字元,可以是空格、定位鍵、換列字元等等。因此 \s+ 就表示由一個或多個空白字元所形成的字串。
因此 re1 = /^[A-Za-z\-]+\s+[A-Za-z\-]+$/ 可以比對由兩個字彙所形成的英文名字,例如 Michael Jordan;而 re2 = /^[A-Za-z\-]+\s+[A-Za-z\-]+\s+[A-Za-z\-]+$/ 則可以比對由三個字彙所形成的英文名字,例如,Jyh-Shing Roger Jang。
下一個例子,則是用通用表示法來驗證電子郵件,例如:
當我們按下「驗證」按鈕時,JavaScript 會呼叫函數 checkEmail( ) 來對填入的資料進行驗證。相關原始碼如下:
對於此範例所用到的通用式 /^.+@.+\..{2,3}$/,說明如下:
- 句號可以比對任一個字元(但不包含換列字元),因此 .+ 代表長度不為零的字串。
- 若要比對「.」本身,由於其原先已經具有特殊意義,所以必須加上反斜線:「\.」。
- .{2,3} 代表長度為 2 或 3 的字元,可以比對國碼(兩個字元)或是 com、edu 等美國地區專用碼。
- 再次說明:^ 代表字串開始位置,$ 代表字串結束位置。
因此 /^.+@.+\..{2,3}$/ 可用來比對一般的 email 帳號,例如 test@cs.nthu.edu.tw 或是 roger_jang@mathworks.com 等,但是此通用式並非滴水不漏,有些不合格的 email 帳號也會比對成功,例如 " @math.com",或是 "test@ .tw",或是 "aa@bb.zz"。若要避開含有空白的 email 帳號,請見下列範例:
相關原始碼如下:
對於此範例所用到的通用式 /^[^\s]+@[^\s]+\.[^\s]{2,3}$/,說明如下:
- \s 代表所有可能的空白字元,包含空白、定位鍵、換列字元等。(但並不包含全形的空白,請特別注意!)
- ^ 在中括弧內是代表「否定」,因此 [^\s]+ 代表「由一個或多個非空白字元」所形成的字串。
- 若要對電郵進行更嚴苛的比對,上述通用式可以改成 /^\w+@\w+\.\w{2,3}$/,其中 \w 代表一個數字、字母或底線,全等於 [a-zA-Z0-9_]。(但這樣嚴苛的標準也可能錯誤地阻擋正常的電郵。)
在以下的範例中,我們設計了一個表單,可以讓使用者輸入任意字串、通用式,以及比對選項,並在通用式比對後,列出比對到的字串,讀者們可以利用此範例,反覆演練,以增進對於通用式的瞭解:
上述範例的原始檔如下:
在上述範例中,我們使用了字串的 match() 方法,來對通用式進行比對,因此 matched = str.match(regexp) 可將比對到的字串送到一個陣列,以便後續處理。
在進行表單資料驗證之前,我們應先進行表單資料修改,例如拿掉不必要的空格、英文字母大小寫轉換等,這些工作也可以由字串的 replace() 方法或通用式的 exec() 方法來達成,這是我們下一節的主題。
JavaScript 程式設計與應用:用於網頁用戶端