2008年7月3日 星期四

javascript新視窗

經常上網的朋友可能會到過這樣一些網站,一進入首頁立刻會彈出一個視窗,或者按一個連接或按鈕彈出,通常在這個視窗裏會顯示一些注意事項、版權信息、警告、歡迎光顧之類的話或者作者想要特別提示的信息。其實制作這樣的頁面效果非常的容易,只要往該頁面的HTML裏加入幾段Javascript代碼即可實現。下面俺就帶您剖析它的奧秘。
【1、最基本的彈出視窗代碼】

其實代碼非常簡單:

<SCRIPT LANGUAGE="javascript">
<!--
window.open ('page.html')
-->
</SCRIPT>
因為著是一段javascripts代碼,所以它們應該放在<SCRIPT LANGUAGE="javascript">標簽和</script>之間。<!-- 和 -->是對一些版本低的瀏覽器起作用,在這些老瀏覽器中不會將標簽中的代碼作為文本顯示出來。要養成這個好習慣啊。
window.open ('page.html') 用於控制彈出新的視窗page.html,如果page.html不與主視窗在同一路徑下,前面應寫明路徑,絕對路徑(http://)和相對路徑(../)均可。用單引號和雙引號都可以,只是不要混用。
這一段代碼可以加入HTML的任意位置,<head>和</head>之間可以,<body>間</body>也可以,越前越早執行,尤其是頁面代碼長,又想使頁面早點彈出就盡量往前放。


【2、經過設置後的彈出視窗】

下面再說一說彈出視窗的設置。只要再往上面的代碼中加一點東西就可以了。
我們來定制這個彈出的視窗的外觀,尺寸大小,彈出的位置以適應該頁面的具體情況。
<SCRIPT LANGUAGE="javascript">
<!--
window.open ('page.html', 'newwindow', 'height=100, width=400, top=0,left=0, toolbar=no, menubar=no, scrollbars=no, resizable=no,location=no, status=no')
file://寫成一行
-->
</SCRIPT>
參數解釋:
<SCRIPT LANGUAGE="javascript"> js腳本開始;
window.open 彈出新視窗的命令;
'page.html' 彈出視窗的文件名;
'newwindow' 彈出視窗的名字(不是文件名),非必須,可用空''代替;
height=100 視窗高度;
width=400 視窗寬度;
top=0 視窗距離屏幕上方的象素值;
left=0 視窗距離屏幕左側的象素值;
toolbar=no 是否顯示工具欄,yes為顯示;
menubar,scrollbars 表示菜單欄和滾動欄。
resizable=no 是否允許改變視窗大小,yes為允許;
location=no 是否顯示地址欄,yes為允許;
status=no 是否顯示狀態欄內的信息(通常是文件已經打開),yes為允許;
</SCRIPT> js腳本結束


【3、用函數控制彈出視窗】

下面是一個完整的代碼。
<html>
<head>
<script LANGUAGE="JavaScript">
<!--
function openwin() { window.open ("page.html", "newwindow", "height=100, width=400, toolbar=
no, menubar=no, scrollbars=no, resizable=no, location=no, status=no")
file://寫成一行
}
file://-->
</script>
</head>
<body onload="openwin()">
...任意的頁面內容...
</body>
</html>
這裏定義了一個函數openwin(),函數內容就是打開一個視窗。在調用它之前沒有任何用途。
怎麼調用呢?
方法一:<body onload="openwin()"> 瀏覽器讀頁面時彈出視窗;
方法二:<body onunload="openwin()"> 瀏覽器離開頁面時彈出視窗;
方法三:用一個連接調用:
<a href="#" onclick="openwin()">打開一個視窗</a>
注意:使用的「#」是虛連接。
方法四:用一個按鈕調用:
<input type="button" onclick="openwin()" value="打開視窗">

【4、同時彈出2個視窗】

對源代碼稍微改動一下:
<script LANGUAGE="JavaScript">
<!--
function openwin()
{ window.open ("page.html", "newwindow", "height=100, width=100, top=0,left=0,toolbar=no, menubar=no, scrollbars=no, resizable=no, location=no, status=no")
file://寫成一行
window.open ("page2.html", "newwindow2", "height=100, width=100, top=100, left=100,toolbar=no, menubar=no, scrollbars=no, resizable=no, location=no, status=no")
file://寫成一行
}
file://-->
</script>
為避免彈出的2個視窗覆蓋,用top和left控制一下彈出的位置不要相互覆蓋即可。最後用上面說過的四種方法調用即可。

注意:2個視窗的name(newwindows和newwindow2)不要相同,或者幹脆全部為空。OK?

【5、主視窗打開文件1.htm,同時彈出小視窗page.html】

如下代碼加入主視窗<head>區:
<script language="javascript">
<!--
function openwin()
{window.open("page.html","","width=200,height=200")
}
file://-->
</script>
加入<body>區:
<a href="1.htm" onclick="openwin()">open</a>即可。

【6、彈出的視窗之定時關閉控制】

下面我們再對彈出的視窗進行一些控制,效果就更好了。如果我們再將一小段代碼加入彈出的頁面(注意是加入到page.html的HTML中,可不是主頁面中,否則...),讓它10秒後自動關閉是不是更酷了?

首先,將如下代碼加入page.html文件的<head>區:
<script language="JavaScript">
function closeit()
{setTimeout("self.close()",10000) file://毫秒}
</script>
然後,再用<body onload="closeit()"> 這一句話代替page.html中原有的<BODY>這一句就可以了。(這一句話千萬不要忘記寫啊!這一句的作用是調用關閉視窗的代碼,10秒鍾後就自行關閉該視窗。)

【7、在彈出視窗中加上一個關閉按鈕】

<FORM>
<INPUT TYPE='BUTTON' VALUE='關閉' onClick='window.close()'>
</FORM>
呵呵,現在更加完美了!

【8、內包含的彈出視窗-一個頁面兩個視窗】

上面的例子都包含兩個視窗,一個是主視窗,另一個是彈出的小視窗。

通過下面的例子,你可以在一個頁面內完成上面的效果。
<html>
<head>
<SCRIPT LANGUAGE="JavaScript">
function openwin()
{OpenWindow=window.open("", "newwin", "height=250, width=250,toolbar=no,scrollbars="+scroll+",menubar=no");
file://寫成一行
OpenWindow.document.write("<TITLE>例子</TITLE>")
OpenWindow.document.write("<BODY BGCOLOR=#ffffff>")
OpenWindow.document.write("<h1>Hello!</h1>")
OpenWindow.document.write("New window opened!")
OpenWindow.document.write("</BODY>")
OpenWindow.document.write("</HTML>")
OpenWindow.document.close()}
</SCRIPT>
</head>
<body>
<a href="#" onclick="openwin()">打開一個視窗</a>
<input type="button" onclick="openwin()" value="打開視窗">
</body>
</html>
看看 OpenWindow.document.write()裏面的代碼不就是標准的HTML嗎?只要按照格式寫更多的行即可。千萬注意多一個標簽或少一個標簽就會出現錯誤。記得用OpenWindow.document.close()結束啊。

【9、終極應用--彈出的視窗之Cookie控制】

回想一下,上面的彈出視窗雖然酷,但是有一點小毛病(沉浸在喜悅之中,一定沒有發現吧?)比如你將上面的腳本放在一個需要頻繁經過的頁面裏(例如首頁),那麼每次刷新這個頁面,視窗都會彈出一次,是不是非常煩人?:-(有解決的辦法嗎?Yes! ;-) Follow me.

我們使用cookie來控制一下就可以了。

首先,將如下代碼加入主頁面HTML的<HEAD>區:
<script>
function openwin()
{window.open("page.html","","width=200,height=200")}
function get_cookie(Name)
{var search = Name + "="
var returnvalue = "";
if (document.cookie.length > 0) {
offset = document.cookie.indexOf(search)
if (offset != -1) {
offset += search.length
end = document.cookie.indexOf(";", offset);
if (end == -1)
end = document.cookie.length;
returnvalue=unescape(document.cookie.substring(offset,end))
}
}
return returnvalue;
}
function loadpopup(){
if (get_cookie('popped')==''){
openwin()
document.cookie="popped=yes"
}
}
</script>
然後,用<body onload="loadpopup()">(注意不是openwin而是loadpop啊!)替換主頁面中原有的<BODY>這一句即可。你可以試著刷新一下這個頁面或重新進入該頁面,視窗再也不會彈出了。真正的Pop-Only-Once!

寫到這裏彈出視窗的制作和應用技巧基本上算是完成了,俺也累壞了,一口氣說了這麼多,希望對正在制作網頁的朋友有所幫助俺就非常欣慰了。

需要注意的是,JS腳本中的的大小寫最好前後保持一致。

javascript只能輸入數字

<body>
<script>
function JHshNumberText()
{
if ( !(((window.event.keyCode >= 48) && (window.event.keyCode <= 57)) (window.event.keyCode == 13) (window.event.keyCode == 46) (window.event.keyCode == 45)))
{window.event.keyCode = 0 ;}
}
</script>
<form name="frm">
<input type="text" name="test" value="" onkeypress="JHshNumberText()">
<input type="button" name="submit" value="submit">
</form>
</body>

啟用/禁用USB

啟用USB將下列機碼儲成enableusb.reg檔
-----------------------------------------------------
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\USBSTOR]"Start"=dword:00000003------------------------------------------------
執行命令regedit /s enableusb.reg

禁用USB將下列機碼儲成disableusb.reg檔
-----------------------------------------------------
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\USBSTOR]"Start"=dword:00000004------------------------------------------------
執行命令regedit /s disableusb.reg

ASP.NET 如何設定強制下載檔案並正確處理中文檔名的問題


我想一般人的作法都是透過設定 HTTP 回應 Content-Disposition 標頭(Header)的方式告知用戶端(Browser)強制下載檔案的,例如:

string fileName = "ExportData.csv";string strContentDisposition = String.Format("{0}; filename=\"{1}\"", "attachment", fileName);

Response.AddHeader("Content-Disposition", strContentDisposition);

透過上述程式碼,就可以讓 Browser 強制下載此頁的內容,也就是該頁的內容(可能是文件或二進位檔案)不會直接在瀏覽器中開啟或下載後直接開啟相關程式(如:Office)。
其中 Content-Disposition 標頭的第一組參數是 attachment,代表此頁唯一個「附件檔」,如果你將 attchment 改成 inline 的話,就代表這是一個內嵌與其他網頁內檔案(如:圖檔、CSS、JavaScript、Flash、...),而這也是「預設」的設定,所以也就等於不加上 Content-Disposition 標頭的情況。
而 Content-Disposition 標頭的第二組參數是 filename,也就是你可以指定下載檔案時預設的儲存檔名,在此範例中的下載檔名是 ExportData.csv

雖然這個小技巧很好用,不過當你的檔名內含「中文字」的時候,卻會發生以下錯誤:

經測試發現,這個問題只會再 IE 出現,當我在使用 Firefox 的時候並不會有這個問題,嚴格算起來應該算是 IE 的 Bug。
我從 MSDN 的 HttpResponse.HeaderEncoding 屬性 說明文件發現 ASP.NET 在回應 HTTP 標頭的時候預設編碼是用 System.Text.UTF8Encoding 類別,但問題是 IE 瀏覽器無法正確解析 UTF-8 的 HTTP Header。從網路上得到的一般性解法就是特別指定 Response.HeaderEncoding 的編碼,因為 IE 瀏覽器在繁體中文的作業系統下可以支援的編碼是 Big5,所以照理說只要設定正確的編碼就能夠正確下載中文檔名,如下程式片段:
Response.HeaderEncoding = Encoding.GetEncoding("big5");
不過經過我測試的結果,這段 Code 在 ASP.NET Development Server 中執行是「完全無效」的,所有的中文字還是以 UTF-8 編碼輸出,但是同一段程式碼在 IIS 6.0 中卻可以正常執行,雖然可以正確輸出 Big5 編碼的 HTTP Header,但是下載後的檔名竟然有幾台機器會變成亂碼,雖然大多數主機下載的檔名是正確的,但此問題依然困擾著我,因為當你設定了 Big5 編碼後,中國大陸簡體中文的用戶又無法下載了,或是下載後檔名一樣變成亂碼。
為了解決這個問題,我不斷的上網尋找資料,不過都沒有人提出有別於設定 Response.HeaderEncoding 的作法,所以就一直試一直試,試了快 4 個鐘頭,結果看到頭暈眼花,還是放棄了。但今天突然靈機一動想說將中文檔名用 Server.UrlPathEncode 方法編碼看看,結果真的成功了!以下是程式碼範例:

string fileName = Server.UrlPathEncode("匯出資料檔080419.csv");string strContentDisposition = String.Format("{0}; filename=\"{1}\"", "attachment", fileName);Response.AddHeader("Content-Disposition", strContentDisposition);

此技巧不但可以正確下載中文檔名,且也不需要設定任何 Response.HeaderEncoding 就可以正常下載,同一段程式碼同時可以給任何支援 UTF-8 的作業系統下載,包括使用簡體中文的大陸用戶也可以正確下載檔案了,真是大快人心啊。
因為我們的目的是「要讓使用者能正確下載含有中文檔名的檔案」且目的也算是達成了,不過如果使用者直接在檔案下載視窗點選「開啟舊檔(O)」的話(如下圖):

IE 會先將該檔案暫存於 IE 的暫存目錄裡並且直接開啟該檔案,不過檔名卻會變成 %e5%8c%af%e5%87%ba%e8%b3%87%e6%96%99%e6%aa%94080419.csv (編碼過的檔名),如果使用者只是想開啟來看一下不存檔的話,那到沒什麼大礙,如果使用者按下「另存新檔」要儲存檔案時,那檔名就變的亂七八糟了,唉~ 殘念!這點真的無解!
另外我也在 Firefox 瀏覽器中測試,發現另存新檔或開啟檔案的檔名也一樣會變成編碼過的檔名( %e5%8c%af%e5%87%ba%e8%b3%87%e6%96%99%e6%aa%94080419.csv ),所以沒辦法一招半式闖江湖,我又調整了一下程式碼,讓 Content-Disposition 標頭中的檔名可以針對使用者透過 IE 瀏覽器下載時將檔案編碼:
string fileName = "匯出資料檔080419.csv";if (Request.Browser.Browser == "IE") { fileName = Server.UrlPathEncode(fileName);}string strContentDisposition = String.Format("{0}; filename=\"{1}\"", "attachment", fileName);Response.AddHeader("Content-Disposition", strContentDisposition);

2008年7月2日 星期三

javascript string 字串功能



JavaScript 在第四版之後,針對通用表示法增加了數個字串方法,這些字串方法的用途很廣,可以列舉如下:



字串方法功能
string.search(re)通用式 re 在某個字串 string 出現的位置
string.match(re)從字串 string 抽取符合通用式 re 的子字串,並以字串陣列傳回
string.replace(re, newStr)將字串 string 符合通用式 re 的部分,代換為 newStr


使用通用表示法及上述的字串方法,我們對字串的處理能力大增,不但可以進行搜尋比對,還可以立刻修改字串(例如:即時修正表單資料),本節將說明這些功能。


若要尋找某個通用式在一個字串的第一次出現的位置,可用字串的 search 方法,例如:

Example(regExpSearch01.htm):



相關原始碼如下:

原始檔(regExpSearch01.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>通用式:搜尋並列出位置</h2>
<hr>

<script>
function regExpMatch(string, pattern, flag){
var regexp = new RegExp(pattern, flag);
var index = string.search(regexp);
alert(index);
}
</script>
<center>
 字串:<input size=40 id=strId value="阿輝伯是李登輝,李炳輝是金門王的搭檔"><br>
通用式:<input size=40 id=patId value="李.輝"><br>
 選項:<input size=40 id=flagId value="g"><br>
<input type="button" value="顯示搜尋結果" onClick="regExpMatch(strId.value, patId.value, flagId.value)">
</center>

<hr>
</body>
</html>



其中 str.search(re) 將會傳回符合 re 的第一個位置(此例為 4)。若字串 str 不符合 re,則回傳值為 -1。若只是要判斷輸入字串是否符合某個通用式,也可以使用 re.test(str),這在上一節已經說明過了。

Hint
str.search(re) 只能用來搜尋某個通用式在一個字串的第一次出現的位置,所以在上述範例中,無論選項的輸入值為何,都只有一個搜尋結果。



使用字串的 match 方法,可在一個字串中,取出符合某個通用表示式的所有子字串,例如:

Example(regExpMatch01.htm):



相關原始碼如下:

原始檔(regExpMatch01.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>通用式:搜尋並列出比對到的字串</h2>
<hr>

<script>
function regExpMatch(string, pattern, flag){
var regexp = new RegExp(pattern, flag);
var matched = string.match(regexp);
alert(matched);
}
</script>
<center>
 字串:<input size=40 id=strId value="阿輝伯是李登輝,李炳輝是金門王的搭檔"><br>
通用式:<input size=40 id=patId value="李.輝"><br>
 選項:<input size=40 id=flagId value="g"><br>
<input type="button" value="顯示搜尋結果" onClick="regExpMatch(strId.value, patId.value, flagId.value)">
</center>

<hr>
</body>
</html>



其中「.」可比對任何一個字元,而傳回的 matched 變數則是一個陣列,包含所比對到的字串。


善用通用表示式及字串的 replace 方法,就可以對字串進行任意修改。例如:

Example(regExpReplace01.htm):



相關原始碼如下:

原始檔(regExpReplace01.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>通用式:搜尋並代換</h2>
<hr>

<script>
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);
}
</script>
<center>
 字串:<input size=40 id=strId value="我愛用通用式,通用式功能強大"><br>
通用式:<input size=40 id=pat1id value="通.式"><br>
新字串:<input size=40 id=pat2id value="正規式"><br>
 選項:<input size=40 id=flagId value=""><br>
<input type="button" value="顯示代換結果" onClick="regExpReplace(strId, pat1id, pat2id, flagId)">
</center>

<hr>
</body>
</html>



在上例中,字串的 replace 方法將符合通用式的第一部分代換成「正規式」,並將新字串傳回給變數 newString。若要將所有的「通用式」改成「正規式」,只需將選項改成「g」就可以了。


處理表單資料時,最常用的資料修正方式就是去除前後的空白。這種例行工作就可以由通用表示法及字串的 replace 方法來輕鬆完成。例如:

Example(regExpReplace02.htm):



在上例中,若按下「修正」,JavaScript 即會將所有的空白部分(含中文大五碼)刪除。程式碼如下:

原始檔(regExpReplace02.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>通用式:修正中文姓名</h2>
<hr>

<script>
function checkChineseName(uiControl) {
uiControl.value = uiControl.value.replace(/[\s ]+/g, ""); // \s & 全形空白
}
</script>
中文大名:<input id=chineseName value=" 金   城  武 ">
<input type=button value="修正" onClick="checkChineseName(chineseName)">

<hr>
</body>
</html>



在上述範例中,[\s ] 是代表英文空白字元或大五碼的全形空白字元,因此 [\s ]+ 就是代表中文中可能出現的空白字串,而 replace(/[\s ]+/g, "") 則是將此類字串全部刪除,也就是代換為空字串。


對於英文的輸入,我們通常要消除字頭及字尾的空白,並將句中的多個空白合成一個空格,例如:

Example(regExpReplace03.htm):



程式碼如下:

原始檔(regExpReplace03.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>通用式:修正英文姓名</h2>
<hr>

<script>
function checkEnglishName(uiControl) {
var str = uiControl.value;
str = str.replace(/^[\s ]+/g, ""); // 刪除頭部的空白字串
str = str.replace(/[\s ]+$/g, ""); // 刪除尾部的空白字串
str = str.replace(/[\s ]+/g, " "); // 將其他空白字串帶換成單一半形空格
uiControl.value = str;
}
</script>
英文大名:<input id=englishName value=" Michael   Jordan ">
<input type=button value="修正" onClick="checkEnglishName(englishName)">

<hr>
</body>
</html>



我們可以使用 "|" 來代表「或」,因此在上述範例中,刪除頭部和尾部的空白字串,可以合成一個敘述,如下:

<br />str = str.replace(/^[\s&#12288;]+|[\s&#12288;]+$/g, "");<br />


如果在通用式使用重複字元時(例如「*」代表重複0次或多次,「+」代表重複至少1次等。),比對之後可能會出現兩種不同的結果,這兩種結果都滿足原來的通用式。此時我們必須知道通用式在進行比對時所採取的原則,才能得到符合我們期望的結果。一般而言,比對原則可以概述如下:


  • 遇到重複字元時,通用表示法會採取「貪心比對」(Greedy Match)來「貪」到越多的字元越好。
  • 若要進行「最小比對」(Minimum Match),則我們必須在重複字元後面加上一個問號,代表「在可能比對成功的情況下,比對越少越好」。

下面是一個範例:

Example(regExpGreedy01.htm):



在上述範例中,第一個通用式是採取預設的「貪心比對」,因此比對到的字串會是 batbetbitbotbut,此字串是在比對成功的情況下、最長的字串。而在第二個通用式中,我們在星號後面加了一個問號,代表採取「最小比對」,因此比對到的字串是 bat,此字串是在比對成功的情況下、最短的字串。此範例的程式碼如下:

原始檔(regExpGreedy01.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>通用式的「貪心比對」與「最小比對」</h2>
<hr>

<script>
str = "fred batbetbitbotbut barney"
document.write("str = "+str+"<br>");
document.write("貪心比對:<br>");
re = /b.*t/;
document.write("re = "+re+"<br>");
document.write("str.match(re) = "+str.match(re)+"<br>");
document.write("最小比對:<br>");
re = /b.*?t/;
document.write("re = "+re+"<br>");
document.write("str.match(re) = "+str.match(re)+"<br>");
</script>

<hr>
</body>
</html>



在使用「貪心比對」時,會採用「越左越貪」的原則,若要推翻此原則,可以適時使用問號,以採用「最小比對」,例如:

Example(regExpGreedy02.htm):



此範例的程式碼如下:

原始檔(regExpGreedy02.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>通用式的「越左越貪」比對方式</h2>
<hr>

<script>
str = "a xx b xxx b xxxx d";
document.write("str = "+str+"<br>");
document.write("越左越貪:<br>");
re = /a(.*)b(.*)d/;
document.write("re = "+re+"<br>");
found = str.match(re);
document.write("RegExp.$1 = "+RegExp.$1+", RegExp.$2 = "+RegExp.$2+"<br>");
document.write("推翻越左越貪:<br>");
re = /a(.*?)b(.*)d/;
document.write("re = "+re+"<br>");
found = str.match(re);
document.write("RegExp.$1 = "+RegExp.$1+", RegExp.$2 = "+RegExp.$2+"<br>");
</script>

<hr>
</body>
</html>



在上例中,我們在通用式中加了括號,符合括號中的比對條件者,將被設定至 RegExp.$1、RegExp.$2 等變數中,以便後續處理。
(為簡化起見,RegExp.$1 可以簡寫成 $1,RegExp.$2 可以簡寫成 $2,依此類推。)此外,在第一個通用式中,由於採取預設的「越左越貪」,所以 RegExp.$1 = "xx b xxx" 且 RegExp.$2 = "xxxx";但在第二個通用式中,由於我們適時使用了問號來進行「最小比對」,所以得到 RegExp.$1 = "xx" 且 RegExp.$2 = "xxx b xxxx"。


以下這個範例,利用 replace() 將一句英文中的前兩個字彙對調:

Example(regExpReplace04.htm):



程式碼如下:

原始檔(regExpReplace04.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>通用式:對調兩個英文字</h2>
<hr>

<script>
function exchangeWord(id) {
var regexp = /(\w+)\s+(\w+)/;
var newString = id.innerHTML.replace(regexp, "$2 $1");
alert("First matched word = " + RegExp.$1);
alert("Second matched word = " + RegExp.$2);
id.innerHTML = newString;
}
</script>
請點選下列文字以對調前兩個英文字:<p>
<div onClick='exchangeWord(this)'>we are the world!</div>

<hr>
</body>
</html>



以下這個範例,利用 replace() 在 onBlur 事件時,先修正文字欄位,再進行驗證:

Example(regExpReplace05.htm):




說明:在 onBlur 事件後,JavaScript 會以通用式來對以下表單元素的值進行修正與驗證。。




Your English name:

value=" Michael J. Fox " onBlur="trimtext(this); checkName(this)">

Your email:

value="test@cs.nthu.edu.twww" onBlur="trimtext(this); checkEmail(this)">


Your password (5 to 8 characters only):

value="123" onBlur="checkPassword(this, 5, 8)">


Your social security number (9 digits):

value="123" onBlur="trimtext(this); checkDigit(this, 9, 9)">



資料驗證


「通用表示法」或「通用式」(Regular expressions)是在 UNIX 世界中發展出來的字串比對技巧,其基本概念是用一套格式簡單、但功能強大的符號來比對複雜的字串,並可對符合比對條件的字串進行修改或其他運算。事實上,UNIX 的許多軟體或指令都支援通用表示法,例如 grep、sed、awk、ed、vi、emacs 等。(但是這些東西大概只有像我這樣的 LKK 才會用吧。)

Hint
若按照字面來翻譯,Regular expressions 應該翻成「正規表示法」或「正規式」,但是我們使用「通用表示法」或「通用式」似乎更能適切地表達其功能。



Netscape 及 IE 在第四版後都支援 JavaScript/VBScript 的通用表示法,特別適用於表單資料的驗證與修改。事實上,JavaScript/VBScript 的通用表示法和 Perl 以及其他 UNIX 相關指令幾乎一模一樣,因此,在本章學到的通用表示法,也可以完全適用於 Perl 或 UNIX 相關指令。(一魚兩吃,真是太棒了!)


由於篇幅限制,我們僅介紹 JavaScript 的通用式;VBScript 的通用式在功能上完全相同,只不過命令格式有所不同,有興趣的讀者,可以參考網路相關資料。


JavaScript 的通用式是一個內建的物件,其建構函數(Construction functoin)為 RegExp,典型用法如下:


re = new RegExp("pattern", "flag")<br />

上述用法也可以簡寫成下列格式:
<br />re = /pattern/flag<br />

其中,pattern 是通用表示法的字串,flag 則是比對的方式。flag 的值可能有三種,分別解釋如下:

  • g:全域比對(Global match)
  • i:忽略大小寫(Ignore case)
  • gi:全域比對並忽略大小寫


舉例來說,我們的身份證字號的基本格式,是由一個英文字母加上九個數字組合而成,如果我們要求使用者輸入身份證字號,就可以使用 JavaScript 的通用表示法來驗證其格式的正確性。例如,我們可用下列表單來要求使用者輸入身份證字號:

Example(regExpID01.htm):



在上例中,我們只要按下「驗證」的按鈕,就會呼叫 checkID() 函數來對文字欄位中的身份證字號進行驗證。相關原始碼如下:

原始檔(regExpID01.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>通用式:簡易身份證字號驗證</h2>
<hr>

<script>
function checkID(string) {
re = /^[A-Z]\d{9}$/;
if (re.test(string))
alert("成功!符合「" + re + "」的格式!");
else
alert("失敗!不符合「" + re + "」的格式!");
}
</script>
身份證字號(第一個英文字母需大寫):<input id=idNumber value=A12345678>
<input type=button value="驗證" onClick="checkID(idNumber.value)">

<hr>
</body>
</html>



在上述範例中,/^[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}$/ 就可以了!

Hint
注意:若不加入 ^ 和 $,那麼 /[A-Z]d{9}/ 就會比對到其他不合法的身份證字號,例如 AGF123456789 或是 F1234567890 等。因此,加入 ^ 和 $ 可保證比對正確的字串一定是由一個大寫英文字母加上九個數字所構成。



事實上,身份證字號本身就有內在的編碼規則,這些規則和使用者的性別有關,因此若要實現完整的表單驗證,就必須應用完整的身份證編碼規則,讀者可參考本章的最後一節。


另一個簡單的例子,是要求使用者輸入信用卡號碼,這是一組 16 個數字的號碼,例如:

Example(regExpCreditCardNumber01.htm):



當我們按下「驗證」按鈕時,JavaScript 會呼叫函數 checkCreditCard( ) 來對填入的資料進行驗證。相關原始碼如下:

原始檔(regExpCreditCardNumber01.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>通用式:簡易信用卡卡號驗證</h2>
<hr>

<script>
function checkCreditCard(string) {
re = /^\d{4}-\d{4}-\d{4}-\d{4}$/;
// re = /^(\d{4}-){3}\d{4}$/; // 這種寫法也可以!
if (re.test(string))
alert("成功!符合「" + re + "」的格式!");
else
alert("失敗!不符合「" + re + "」的格式!");
}
</script>
信用卡號碼:<input id=creditCardNumber value=1234-5678-9012-3456>
<input type=button value="驗證" onClick="checkCreditCard(creditCardNumber.value)">

<hr>
</body>
</html>



在上例中,很顯然地,/^\d{4}-\d{4}-\d{4}-\d{4}$/ 就代表正確的信用卡格式。很明顯的,使用通用式會讓程式碼簡潔很多,而且會大大提高程式碼的正確性。(請和前面章節的類似範例 formValidation02.htm 比較看看。)但要注意的是,信用卡卡號本身就有內在的較複雜編碼規則,因此若要實現完整的表單驗證,就必須應用完整的信用卡卡號編碼規則,讀者可參考本章的最後一節。


如果重複的部分多於一個字母,我們就必須將需要重複的部分放在小括號內,再加上由大括號包夾的重複次數,例如,上述範例的通用式 /^\d{4}-\d{4}-\d{4}-\d{4}$/,也可以寫成 /^(\d{4}-){3}\d{4}$/,請試試看!


下一個例子,則是用通用表示法來驗證使用者的英文名字,例如:

Example(regExpEnglishName01.htm):



當我們按下「驗證」按鈕時,JavaScript 會呼叫函數 checkEnglishName( ) 來對填入的資料進行驗證。相關原始碼如下:

原始檔(regExpEnglishName01.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>通用式:簡易英文名字驗證</h2>
<hr>

<script>
function checkEnglishName(string) {
re1 = /^[A-Za-z\-]+\s+[A-Za-z\-]+$/;
re2 = /^[A-Za-z\-]+\s+[A-Za-z\-]+\s+[A-Za-z\-]+$/;
if (re1.test(string) || re2.test(string))
alert("成功!符合「" + re1 + "」或「" + re2 + "」的格式!");
else
alert("失敗!不符合「" + re1 + "」或「" + re2 + "」的格式!");
}
</script>
你的英文全名(格式:First Last 或 First Middle Last):<input id=englishName value="Jyh-Shing Roger Jang">
<input type=button value="驗證" onClick="checkEnglishName(englishName.value)">

<hr>
</body>
</html>



對於上述範例程式,我們說明如下:


  • [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。


下一個例子,則是用通用表示法來驗證電子郵件,例如:

Example(regExpEmail01.htm):



相關原始碼如下:

原始檔(regExpEmail02.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>通用式:電子郵件格式驗證(可以避開含有空白的電子郵件帳號)</h2>
<hr>

<script>
function checkEmail(string) {
re = /^[^\s]+@[^\s]+\.[^\s]{2,3}$/;
if (re.test(string))
alert("成功!符合「" + re + "」的格式!");
else
alert("失敗!不符合「" + re + "」的格式!");
}
</script>
電子郵件:<input id=email value="jang@cs.n thu.edu.tw">
<input type=button value="驗證" onClick="checkEmail(email.value)">

<hr>
</body>
</html>



對於此範例所用到的通用式 /^[^\s]+@[^\s]+\.[^\s]{2,3}$/,說明如下:


  • \s 代表所有可能的空白字元,包含空白、定位鍵、換列字元等。(但並不包含全形的空白,請特別注意!)
  • ^ 在中括弧內是代表「否定」,因此 [^\s]+ 代表「由一個或多個非空白字元」所形成的字串。

Hint
請注意:^ 在一般通用表示法的意義是「字串開始的位置」,但是一旦放在中括弧內,則是代表「否定」或「非」。




在以下的範例中,我們設計了一個表單,可以讓使用者輸入任意字串、通用式,以及比對選項,並在通用式比對後,列出比對到的字串,讀者們可以利用此範例,反覆演練,以增進對於通用式的瞭解:

Example(regExpTest01.htm):



上述範例的原始檔如下:

原始檔(regExpTest01.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>通用式:完整測試頁</h2>
<hr>

<script>
function showMatched(form){
var regexp = new RegExp(form.pattern.value, form.flag.value);
var str = form.string.value;
var matched = str.match(regexp);
if (matched) {
var dispstr = matched.length + " 個比對到的字串:";
for (var i=0; i<matched.length; i++)
dispstr = dispstr + "\n" + matched[i];
alert(dispstr);
} else
alert("沒有比對到任何字串!");
}
</script>
<form>
<table align=center>
<tr><td align=right>字串:
<td><input type=text size=30 name=string value="There are 10 rookies coming at 3 o'clock!">
<tr><td align=right>通用式:
<td><input type=text size=30 name=pattern value=" \w+ "> (範例:\d{2,3}, T.*a, T.*?a)
<tr><td align=right>選項:
<td><input type=text size=30 name=flag value="g"> (g, i, or gi)
<tr><td align=right><br>
<td><input type="button" value="顯示比對到的字串" onClick="showMatched(this.form)"><input type="reset">
</table>
</form>

<hr>
</body>
</html>



在上述範例中,我們使用了字串的 match() 方法,來對通用式進行比對,因此 matched = str.match(regexp) 可將比對到的字串送到一個陣列,以便後續處理。


在進行表單資料驗證之前,我們應先進行表單資料修改,例如拿掉不必要的空格、英文字母大小寫轉換等,這些工作也可以由字串的 replace() 方法或通用式的 exec() 方法來達成,這是我們下一節的主題。