精品视频在线播放色网色视频,一本色道久久综合亚洲精品酒店,免费亚洲精品视频http://www.aygfsteel.com/snoics/category/3769.html<SCRIPT language=JavaScript> <!--// var version = "other" ; browserName = navigator.appName; browserVer = parseInt(navigator.appVersion); if (browserName == "Netscape" && browserVer >= 3) version = "n3"; else if (browserName == "Netscape" && browserVer < 3) version = "n2"; else if (browserName == "Microsoft Internet Explorer" && browserVer >= 4) version = "e4"; else if (browserName == "Microsoft Internet Explorer" && browserVer < 4) version = "e3"; function marquee1() { if (version == "e4") { document.write("<marquee behavior=scroll direction=up width=367 height=135 scrollamount=1 scrolldelay=100>") } } function marquee2() { if (version == "e4") { document.write("</marquee>") } } //--> </SCRIPT> <SCRIPT language=JavaScript>marquee1();</SCRIPT> <SCRIPT> <!-- var from = 1; var to = 4; var delay = 55; //閃的速度 var glowColor = "#FFCC00";//顏色 var i = to; var j = 0; textPulseDown(); function textPulseUp() { if (!document.all) return if (i < to) { //theText.style.filter = "Glow(Color=" + glowColor + ", Strength=" + i + ")"; i++; theTimeout = setTimeout('textPulseUp()',delay); return 0; } if (i = to) { theTimeout = setTimeout('textPulseDown()',delay); return 0; } } function textPulseDown() { if (!document.all) return if (i > from) { //theText.style.filter = "Glow(Color=" + glowColor + ", Strength=" + i + ")"; i--; theTimeout = setTimeout('textPulseDown()',delay); return 0; } if (i = from) { theTimeout = setTimeout('textPulseUp()',delay); return 0; } } //--> </SCRIPT> <FONT style="COLOR: white; FILTER: glow(color=#9966FF,strength=5); HEIGHT: 10px; PADDING-BOTTOM: 3px; PADDING-LEFT: 1px; PADDING-RIGHT: 1px; PADDING-TOP: 3px"> <br> 天很高,云很淡 風(fēng)很輕,海很藍(lán)<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 牽著手<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 在浪漫的沙灘上,留下兩行清晰的腳印...... </font>zh-cnFri, 02 Mar 2007 06:48:49 GMTFri, 02 Mar 2007 06:48:49 GMT60Java中文處理學(xué)習(xí)筆記——Hello Unicode [轉(zhuǎn)]http://www.aygfsteel.com/snoics/articles/16575.htmlsnoicssnoicsMon, 24 Oct 2005 06:27:00 GMThttp://www.aygfsteel.com/snoics/articles/16575.htmlhttp://www.aygfsteel.com/snoics/comments/16575.htmlhttp://www.aygfsteel.com/snoics/articles/16575.html#Feedback0http://www.aygfsteel.com/snoics/comments/commentRss/16575.htmlhttp://www.aygfsteel.com/snoics/services/trackbacks/16575.html閱讀全文

snoics 2005-10-24 14:27 發(fā)表評(píng)論
]]>
Unicode 問答集 [轉(zhuǎn)]http://www.aygfsteel.com/snoics/articles/16574.htmlsnoicssnoicsMon, 24 Oct 2005 06:24:00 GMThttp://www.aygfsteel.com/snoics/articles/16574.htmlhttp://www.aygfsteel.com/snoics/comments/16574.htmlhttp://www.aygfsteel.com/snoics/articles/16574.html#Feedback0http://www.aygfsteel.com/snoics/comments/commentRss/16574.htmlhttp://www.aygfsteel.com/snoics/services/trackbacks/16574.html圖標(biāo)

Unicode 問答集

問:什么是Unicode?
答:Unicode給每個(gè)字符提供了一個(gè)唯一的數(shù)字,不論是什么平臺(tái),不論是什么程序,不論什么語言。Unicode標(biāo)準(zhǔn)已經(jīng)被這些工業(yè)界的領(lǐng)導(dǎo)們所采用,例如:Apple, HP, IBM, JustSystem, Microsoft, Oracle, SAP, Sun, Sybase, Unisys和其它許多公司。最新的標(biāo)準(zhǔn)都需要Unicode,例如XML, Java, ECMAScript (JavaScript), LDAP, CORBA 3.0, WML等等,并且,Unicode是實(shí)現(xiàn)ISO/IEC 10646的正規(guī)方式。許多操作系統(tǒng),所有最新的瀏覽器和許多其他產(chǎn)品都支持它。Unicode標(biāo)準(zhǔn)的出現(xiàn)和支持它工具的存在,是近來全球軟件技術(shù)最重要的發(fā)展趨勢(shì)。

問:為什么使用Unicode?
答:基本上,計(jì)算機(jī)只是處理數(shù)字。它們指定一個(gè)數(shù)字,來儲(chǔ)存字母或其他字符。在創(chuàng)造Unicode之前,有數(shù)百種指定這些數(shù)字的編碼系統(tǒng)。沒有一個(gè)編碼可以包含足夠的字符:例如,單單歐州共同體就需要好幾種不同的編碼來包括所有的語言。即使是單一種語言,例如英語,也沒有哪一個(gè)編碼可以適用于所有的字母,標(biāo)點(diǎn)符號(hào),和常用的技術(shù)符號(hào)。這些編碼系統(tǒng)也會(huì)互相沖突。也就是說,兩種編碼可能使用相同的數(shù)字代表兩個(gè)不同的字符,或使用不同的數(shù)字代表相同的字符。任何一臺(tái)特定的計(jì)算機(jī)(特別是服務(wù)器)都需要支持許多不同的編碼,但是,不論什么時(shí)候數(shù)據(jù)通過不同的編碼或平臺(tái)之間,那些數(shù)據(jù)總會(huì)有損壞的危險(xiǎn)。

問:舉個(gè)例子吧。
答:比如,簡(jiǎn)體中文(GB)、繁體中文(BIG5)、日文中,“趙”都是一個(gè)字,但是編碼不同。在不同的編碼下,BIG5的趙是0xBBAF,而0xBBAF在GB里面就被顯示為“化”,這就是亂碼。而Unicode采用統(tǒng)一的編碼,“趙”只有一個(gè),不必管他在哪種文字里。

問:Unicode的優(yōu)點(diǎn)是什么?
答:舉一個(gè)最明顯的例子就是Windows 2000/XP以及微軟Office2000及其后的產(chǎn)品。因?yàn)檫@些軟件都是Unicode內(nèi)核,因此,無論何種文字,都可以在上面正常顯示,而且是同屏顯示。以前,簡(jiǎn)體中文的Word文件拿到英文版打開就會(huì)是亂碼,簡(jiǎn)體中文的程序在Windows英文版上運(yùn)行會(huì)出現(xiàn)亂碼,而現(xiàn)在一切都解決了。

問:中國京劇戲考為什么使用Unicode?
答:因?yàn)橛行﹦”局械纳ё?,只在擴(kuò)展字庫或繁體字庫中才有,有的甚至沒有。而Unicode不僅包含了所有常用字和大部分生僻字,而且因?yàn)槠淇蓴U(kuò)展,在現(xiàn)在沒有的情況下,將來也是可以擴(kuò)充的。例如最新的Unicode 4.0標(biāo)準(zhǔn),較3.0增加了很多生僻字。目前有70207個(gè)漢字。再有一點(diǎn)就是Unicode在將來會(huì)取代現(xiàn)有的GBK及BIG5。

問:我如何能夠看到不是亂碼的劇本?
答:如果您閱讀PDF的格式,只需要有Adobe Reader即可。如果您是在網(wǎng)站上直接閱讀劇本,有時(shí)可能會(huì)出現(xiàn)亂碼,請(qǐng)查看菜單(或右鍵單擊劇本)中,選擇編碼,然后點(diǎn)Unicode (UTF-8) 即可。注意,有些字在早期的 Unicode 定義中還沒有,所以建議您閱讀PDF格式的劇本。詳情請(qǐng)見這里。



snoics 2005-10-24 14:24 發(fā)表評(píng)論
]]>
關(guān)于Unicode [轉(zhuǎn)]http://www.aygfsteel.com/snoics/articles/16572.htmlsnoicssnoicsMon, 24 Oct 2005 06:21:00 GMThttp://www.aygfsteel.com/snoics/articles/16572.htmlhttp://www.aygfsteel.com/snoics/comments/16572.htmlhttp://www.aygfsteel.com/snoics/articles/16572.html#Feedback0http://www.aygfsteel.com/snoics/comments/commentRss/16572.htmlhttp://www.aygfsteel.com/snoics/services/trackbacks/16572.html關(guān)于Unicode

Unicode是一個(gè)16位的字符集,它可以移植到所有主要的計(jì)算機(jī)平臺(tái)并且覆蓋幾乎整個(gè)世界。它也是單一地區(qū)的;它不包括代碼頁或者其它讓軟件很難讀寫和測(cè)試的復(fù)雜的東西?,F(xiàn)在還沒有一個(gè)合理的多平臺(tái)的字符集可以和它競(jìng)爭(zhēng)。由于以上原因,Trolltech公司從Qt 2.0開始選擇Unicode作為它天然的字符集。

在互聯(lián)網(wǎng)上關(guān)于Unicode的信息。

Unicode協(xié)會(huì)提供了大量的文檔,包括

標(biāo)準(zhǔn)

標(biāo)準(zhǔn)當(dāng)前的版本是3.0.1。

Qt中的Unicode

在Qt中,和大多數(shù)使用Qt的應(yīng)用程序中,幾乎所有的或全部的用戶可見的字符串都被使用Unicode方式存儲(chǔ)。Qt提供了:

  • 對(duì)于文件輸入輸出,和傳統(tǒng)的編碼格式的互譯——請(qǐng)看QTextCodecQTextStream。
  • 從輸入法和8位鍵盤輸入的翻譯。
  • 對(duì)于屏幕上顯示,翻譯到傳統(tǒng)字符集。
  • 一個(gè)字符串類,QString,存儲(chǔ)Unicode字符,它支持包括快速的(高速緩存的)和US-ASCII互譯的C字符串的移植,并且支持所有常用的字符串操作。
  • 在適當(dāng)?shù)臅r(shí)候使用支持Unicode的窗口部件。
  • Unicode支持在Windows 95/98/NT/2000上的檢測(cè),這樣Qt就可以在那些甚至不支持Unicode的Windows平臺(tái)上提供Unicode。

為了獲得Unicode的益處,我們建議使用QString來存儲(chǔ)所有用戶可見的字符串并且使用QTextStream來處理所有文本文件輸入輸出。在你寫的任何一個(gè)自定制的窗口部件中使用QKeyEvent::text()來處理鍵盤輸入;它對(duì)于西歐或者北美的速度較慢的打字員來說沒有什么不同的,但是對(duì)于那些速度較快或者使用特殊輸入法的人們來說使用text()是有好處的。

在Qt中所有可能是用戶可見字符串的函數(shù)參數(shù),QLabel::setText()和很多其它函數(shù),使用const QString &來作為類型。QString對(duì)于像下面這樣的const char *工作的

        myLabel->setText( "Hello, Dolly!" );

提供了隱式調(diào)用。還有一個(gè)函數(shù)QObject::tr()也提供翻譯支持,像這樣:

        myLabel->setText( tr("Hello, Dolly!") );

tr()(有時(shí)被簡(jiǎn)化)從const char *映射到Unicode字符串,并且使用QTranslator對(duì)象來進(jìn)行這個(gè)映射。

程序需要和其它程序進(jìn)行通訊或者使用傳統(tǒng)文件格式進(jìn)行讀寫文件,Qt提供了大量的內(nèi)置的QTextCodec類,這些類知道如何在Unicode和傳統(tǒng)編碼之間進(jìn)行翻譯。

默認(rèn)地,和const char *的互相轉(zhuǎn)換使用基于本地的編碼解碼器。無論如何,程序都能夠很容易地找到其它地區(qū)的編碼解碼器,并且可以對(duì)于任何一個(gè)打開的文件或者網(wǎng)絡(luò)連接使用一個(gè)特殊的編碼解碼器。安裝那些內(nèi)置的編碼解碼器不支持新的編碼解碼器也是很容易的。(寫這篇文檔的時(shí)候,越南語/VISCII就是一個(gè)這樣的例子。)

盡管US-ASCII和ISO-8859-1是非常普通的,這里也提供了可以和它們互相映射的特別快的函數(shù)。舉例來說,打開一個(gè)應(yīng)用程序的圖標(biāo)也許會(huì)這樣做:

        QFile f( QString::fromLatin1("appicon.png") );

關(guān)于輸出,Qt對(duì)于從Unicode到任何一個(gè)系統(tǒng)和字體提供的編碼的轉(zhuǎn)換作出了最大的努力?;诓僮飨到y(tǒng)、本地和字體的可用性和Qt對(duì)所使用的字符的支持,這種轉(zhuǎn)換也許是好的,也許是壞的。我們將在即將推出的版本中繼續(xù)改進(jìn),以最普通的地區(qū)編碼作為重點(diǎn)。


Copyright ? 2002 Trolltech Trademarks 譯者:Cavendish
Qt 3.0.5版


snoics 2005-10-24 14:21 發(fā)表評(píng)論
]]>
UTF-8 and Unicode FAQ [轉(zhuǎn)]http://www.aygfsteel.com/snoics/articles/16571.htmlsnoicssnoicsMon, 24 Oct 2005 06:19:00 GMThttp://www.aygfsteel.com/snoics/articles/16571.htmlhttp://www.aygfsteel.com/snoics/comments/16571.htmlhttp://www.aygfsteel.com/snoics/articles/16571.html#Feedback0http://www.aygfsteel.com/snoics/comments/commentRss/16571.htmlhttp://www.aygfsteel.com/snoics/services/trackbacks/16571.htmlUTF-8 and Unicode FAQ

by Markus Kuhn

中國LINUX論壇翻譯小組 xLoneStar[譯] 2000年2月

這篇文章說明了在 POSIX 系統(tǒng) (Linux,Unix) 上使用 Unicode/UTF-8 所需要的信息. 在將來不遠(yuǎn)的幾年里, Unicode 已經(jīng)很接近于取代 ASCII 與 Latin-1 編碼的位置了. 它不僅允許你處理處理事實(shí)上存在于地球上的任何語言文字, 而且提供了一個(gè)全面的數(shù)學(xué)與技術(shù)符號(hào)集, 因此可以簡(jiǎn)化科學(xué)信息交換.

UTF-8 編碼提供了一種簡(jiǎn)便而向后兼容的方法, 使得那種完全圍繞 ASCII 設(shè)計(jì)的操作系統(tǒng), 比如 Unix, 也可以使用 Unicode. UTF-8 就是 Unix, Linux 已經(jīng)類似的系統(tǒng)使用 Unicode 的方式. 現(xiàn)在是你了解它的時(shí)候了.

什么是 UCS 和 ISO 10646?

國際標(biāo)準(zhǔn) ISO 10646 定義了 通用字符集 (Universal Character Set, UCS). UCS 是所有其他字符集標(biāo)準(zhǔn)的一個(gè)超集. 它保證與其他字符集是雙向兼容的. 就是說, 如果你將任何文本字符串翻譯到 UCS格式, 然后再翻譯回原編碼, 你不會(huì)丟失任何信息.

UCS 包含了用于表達(dá)所有已知語言的字符. 不僅包括拉丁語,希臘語, 斯拉夫語,希伯來語,阿拉伯語,亞美尼亞語和喬治亞語的描述, 還包括中文, 日文和韓文這樣的象形文字, 以及 平假名, 片假名, 孟加拉語, 旁遮普語果魯穆奇字符(Gurmukhi), 泰米爾語, 印.埃納德語(Kannada), Malayalam, 泰國語, 老撾語, 漢語拼音(Bopomofo), Hangul, Devangari, Gujarati, Oriya, Telugu 以及其他數(shù)也數(shù)不清的語. 對(duì)于還沒有加入的語言, 由于正在研究怎樣在計(jì)算機(jī)中最好地編碼它們, 因而最終它們都將被加入. 這些語言包括 Tibetian, 高棉語, Runic(古代北歐文字), 埃塞俄比亞語, 其他象形文字, 以及各種各樣的印-歐語系的語言, 還包括挑選出來的藝術(shù)語言比如 Tengwar, Cirth 和 克林貢語(Klingon). UCS 還包括大量的圖形的, 印刷用的, 數(shù)學(xué)用的和科學(xué)用的符號(hào), 包括所有由 TeX, Postscript, MS-DOS,MS-Windows, Macintosh, OCR 字體, 以及許多其他字處理和出版系統(tǒng)提供的字符.

ISO 10646 定義了一個(gè) 31 位的字符集. 然而, 在這巨大的編碼空間中, 迄今為止只分配了前 65534 個(gè)碼位 (0x0000 到 0xFFFD). 這個(gè) UCS 的 16位子集稱為 基本多語言面 (Basic Multilingual Plane, BMP). 將被編碼在 16 位 BMP 以外的字符都屬于非常特殊的字符(比如象形文字), 且只有專家在歷史和科學(xué)領(lǐng)域里才會(huì)用到它們. 按當(dāng)前的計(jì)劃, 將來也許再也不會(huì)有字符被分配到從 0x000000 到 0x10FFFF 這個(gè)覆蓋了超過 100 萬個(gè)潛在的未來字符的 21 位的編碼空間以外去了. ISO 10646-1 標(biāo)準(zhǔn)第一次發(fā)表于 1993 年, 定義了字符集與 BMP 中內(nèi)容的架構(gòu). 定義 BMP 以外的字符編碼的第二部分 ISO 10646-2 正在準(zhǔn)備中, 但也許要過好幾年才能完成. 新的字符仍源源不斷地加入到 BMP 中, 但已經(jīng)存在的字符是穩(wěn)定的且不會(huì)再改變了.

UCS 不僅給每個(gè)字符分配一個(gè)代碼, 而且賦予了一個(gè)正式的名字. 表示一個(gè) UCS 或 Unicode 值的十六進(jìn)制數(shù), 通常在前面加上 "U+", 就象 U+0041 代表字符"拉丁大寫字母A". UCS 字符 U+0000 到 U+007F 與 US-ASCII(ISO 646) 是一致的, U+0000 到 U+00FF 與 ISO 8859-1(Latin-1) 也是一致的. 從 U+E000 到 U+F8FF, 已經(jīng) BMP 以外的大范圍的編碼是為私用保留的.

什么是組合字符?

UCS里有些編碼點(diǎn)分配給了 組合字符.它們類似于打字機(jī)上的無間隔重音鍵. 單個(gè)的組合字符不是一個(gè)完整的字符. 它是一個(gè)類似于重音符或其他指示標(biāo)記, 加在前一個(gè)字符后面. 因而, 重音符可以加在任何字符后面. 那些最重要的被加重的字符, 就象普通語言的正字法(orthographies of common languages)里用到的那種, 在 UCS 里都有自己的位置, 以確保同老的字符集的向后兼容性. 既有自己的編碼位置, 又可以表示為一個(gè)普通字符跟隨一個(gè)組合字符的被加重字符, 被稱為 預(yù)作字符(precomposed characters). UCS 里的預(yù)作字符是為了同沒有預(yù)作字符的舊編碼, 比如 ISO 8859, 保持向后兼容性而設(shè)的. 組合字符機(jī)制允許在任何字符后加上重音符或其他指示標(biāo)記, 這在科學(xué)符號(hào)中特別有用, 比如數(shù)學(xué)方程式和國際音標(biāo)字母, 可能會(huì)需要在一個(gè)基本字符后組合上一個(gè)或多個(gè)指示標(biāo)記.

組合字符跟隨著被修飾的字符. 比如, 德語中的元音變音字符 ("拉丁大寫字母A 加上分音符"), 既可以表示為 UCS 碼 U+00C4 的預(yù)作字符, 也可以表示成一個(gè)普通 "拉丁大寫字母A" 跟著一個(gè)"組合分音符":U+0041 U+0308 這樣的組合. 當(dāng)需要堆疊多個(gè)重音符, 或在一個(gè)基本字符的上面和下面都要加上組合標(biāo)記時(shí), 可以使用多個(gè)組合字符. 比如在泰國文中, 一個(gè)基本字符最多可加上兩個(gè)組合字符.

什么是 UCS 實(shí)現(xiàn)級(jí)別?

不是所有的系統(tǒng)都需要支持象組合字符這樣的 UCS 里所有的先進(jìn)機(jī)制. 因此 ISO 10646 指定了下列三種實(shí)現(xiàn)級(jí)別:

級(jí)別1
不支持組合字符和 Hangul Jamo 字符 (一種特別的, 更加復(fù)雜的韓國文的編碼, 使用兩個(gè)或三個(gè)子字符來編碼一個(gè)韓文音節(jié))
級(jí)別2
類似于級(jí)別1, 但在某些文字中, 允許一列固定的組合字符 (例如, 希伯來文, 阿拉伯文, Devangari, 孟加拉語, 果魯穆奇語, Gujarati, Oriya, 泰米爾語, Telugo, 印.埃納德語, Malayalam, 泰國語和老撾語). 如果沒有這最起碼的幾個(gè)組合字符, UCS 就不能完整地表達(dá)這些語言.
級(jí)別3
支持所有的 UCS 字符, 例如數(shù)學(xué)家可以在任意一個(gè)字符上加上一個(gè) tilde(顎化符號(hào),西班牙語字母上面的~)或一個(gè)箭頭(或兩者都加).

什么是 Unicode?

歷史上, 有兩個(gè)獨(dú)立的, 創(chuàng)立單一字符集的嘗試. 一個(gè)是國際標(biāo)準(zhǔn)化組織(ISO)的 ISO 10646 項(xiàng)目, 另一個(gè)是由(一開始大多是美國的)多語言軟件制造商組成的協(xié)會(huì)組織的 Unicode 項(xiàng)目. 幸運(yùn)的是, 1991年前后, 兩個(gè)項(xiàng)目的參與者都認(rèn)識(shí)到, 世界不需要兩個(gè)不同的單一字符集. 它們合并雙方的工作成果, 并為創(chuàng)立一個(gè)單一編碼表而協(xié)同工作. 兩個(gè)項(xiàng)目仍都存在并獨(dú)立地公布各自的標(biāo)準(zhǔn), 但 Unicode 協(xié)會(huì)和 ISO/IEC JTC1/SC2 都同意保持 Unicode 和 ISO 10646 標(biāo)準(zhǔn)的碼表兼容, 并緊密地共同調(diào)整任何未來的擴(kuò)展.

那么 Unicode 和 ISO 10646 不同在什么地方?

Unicode 協(xié)會(huì)公布的 Unicode 標(biāo)準(zhǔn) 嚴(yán)密地包含了 ISO 10646-1 實(shí)現(xiàn)級(jí)別3的基本多語言面. 在兩個(gè)標(biāo)準(zhǔn)里所有的字符都在相同的位置并且有相同的名字.

Unicode 標(biāo)準(zhǔn)額外定義了許多與字符有關(guān)的語義符號(hào)學(xué), 一般而言是對(duì)于實(shí)現(xiàn)高質(zhì)量的印刷出版系統(tǒng)的更好的參考. Unicode 詳細(xì)說明了繪制某些語言(比如阿拉伯語)表達(dá)形式的算法, 處理雙向文字(比如拉丁與希伯來文混合文字)的算法和 排序與字符串比較 所需的算法, 以及其他許多東西.

另一方面, ISO 10646 標(biāo)準(zhǔn), 就象廣為人知的 ISO 8859 標(biāo)準(zhǔn)一樣, 只不過是一個(gè)簡(jiǎn)單的字符集表. 它指定了一些與標(biāo)準(zhǔn)有關(guān)的術(shù)語, 定義了一些編碼的別名, 并包括了規(guī)范說明, 指定了怎樣使用 UCS 連接其他 ISO 標(biāo)準(zhǔn)的實(shí)現(xiàn), 比如 ISO 6429 和 ISO 2022. 還有一些與 ISO 緊密相關(guān)的, 比如 ISO 14651 是關(guān)于 UCS 字符串排序的.

考慮到 Unicode 標(biāo)準(zhǔn)有一個(gè)易記的名字, 且在任何好的書店里的 Addison-Wesley 里有, 只花費(fèi) ISO 版本的一小部分, 且包括更多的輔助信息, 因而它成為使用廣泛得多的參考也就不足為奇了. 然而, 一般認(rèn)為, 用于打印 ISO 10646-1 標(biāo)準(zhǔn)的字體在某些方面的質(zhì)量要高于用于打印 Unicode 2.0的. 專業(yè)字體設(shè)計(jì)者總是被建議說要兩個(gè)標(biāo)準(zhǔn)都實(shí)現(xiàn), 但一些提供的樣例字形有顯著的區(qū)別. ISO 10646-1 標(biāo)準(zhǔn)同樣使用四種不同的風(fēng)格變體來顯示表意文字如中文, 日文和韓文 (CJK), 而 Unicode 2.0 的表里只有中文的變體. 這導(dǎo)致了普遍的認(rèn)為 Unicode 對(duì)日本用戶來說是不可接收的傳說, 盡管是錯(cuò)誤的.

什么是 UTF-8?

首先 UCS 和 Unicode 只是分配整數(shù)給字符的編碼表. 現(xiàn)在存在好幾種將一串字符表示為一串字節(jié)的方法. 最顯而易見的兩種方法是將 Unicode 文本存儲(chǔ)為 2 個(gè) 或 4 個(gè)字節(jié)序列的串. 這兩種方法的正式名稱分別為 UCS-2 和 UCS-4. 除非另外指定, 否則大多數(shù)的字節(jié)都是這樣的(Bigendian convention). 將一個(gè) ASCII 或 Latin-1 的文件轉(zhuǎn)換成 UCS-2 只需簡(jiǎn)單地在每個(gè) ASCII 字節(jié)前插入 0x00. 如果要轉(zhuǎn)換成 UCS-4, 則必須在每個(gè) ASCII 字節(jié)前插入三個(gè) 0x00.

在 Unix 下使用 UCS-2 (或 UCS-4) 會(huì)導(dǎo)致非常嚴(yán)重的問題. 用這些編碼的字符串會(huì)包含一些特殊的字符, 比如 '\0' 或 '/', 它們?cè)?文件名和其他 C 庫函數(shù)參數(shù)里都有特別的含義. 另外, 大多數(shù)使用 ASCII 文件的 UNIX 下的工具, 如果不進(jìn)行重大修改是無法讀取 16 位的字符的. 基于這些原因, 在文件名, 文本文件, 環(huán)境變量等地方, UCS-2 不適合作為 Unicode 的外部編碼.

在 ISO 10646-1 Annex RRFC 2279 里定義的 UTF-8 編碼沒有這些問題. 它是在 Unix 風(fēng)格的操作系統(tǒng)下使用 Unicode 的明顯的方法.

UTF-8 有一下特性:

  • UCS 字符 U+0000 到 U+007F (ASCII) 被編碼為字節(jié) 0x00 到 0x7F (ASCII 兼容). 這意味著只包含 7 位 ASCII 字符的文件在 ASCII 和 UTF-8 兩種編碼方式下是一樣的.
  • 所有 >U+007F 的 UCS 字符被編碼為一個(gè)多個(gè)字節(jié)的串, 每個(gè)字節(jié)都有標(biāo)記位集. 因此, ASCII 字節(jié) (0x00-0x7F) 不可能作為任何其他字符的一部分.
  • 表示非 ASCII 字符的多字節(jié)串的第一個(gè)字節(jié)總是在 0xC0 到 0xFD 的范圍里, 并指出這個(gè)字符包含多少個(gè)字節(jié). 多字節(jié)串的其余字節(jié)都在 0x80 到 0xBF 范圍里. 這使得重新同步非常容易, 并使編碼無國界, 且很少受丟失字節(jié)的影響.
  • 可以編入所有可能的 231個(gè) UCS 代碼
  • UTF-8 編碼字符理論上可以最多到 6 個(gè)字節(jié)長(zhǎng), 然而 16 位 BMP 字符最多只用到 3 字節(jié)長(zhǎng).
  • Bigendian UCS-4 字節(jié)串的排列順序是預(yù)定的.
  • 字節(jié) 0xFE 和 0xFF 在 UTF-8 編碼中從未用到.

下列字節(jié)串用來表示一個(gè)字符. 用到哪個(gè)串取決于該字符在 Unicode 中的序號(hào).

U-00000000 - U-0000007F: 0xxxxxxx
U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

xxx 的位置由字符編碼數(shù)的二進(jìn)制表示的位填入. 越靠右的 x 具有越少的特殊意義. 只用最短的那個(gè)足夠表達(dá)一個(gè)字符編碼數(shù)的多字節(jié)串. 注意在多字節(jié)串中, 第一個(gè)字節(jié)的開頭"1"的數(shù)目就是整個(gè)串中字節(jié)的數(shù)目.

例如: Unicode 字符 U+00A9 = 1010 1001 (版權(quán)符號(hào)) 在 UTF-8 里的編碼為:

11000010 10101001 = 0xC2 0xA9

而字符 U+2260 = 0010 0010 0110 0000 (不等于) 編碼為:

11100010 10001001 10100000 = 0xE2 0x89 0xA0

這種編碼的官方名字拼寫為 UTF-8, 其中 UTF 代表 UCS Transformation Format. 請(qǐng)勿在任何文檔中用其他名字 (比如 utf8 或 UTF_8) 來表示 UTF-8, 當(dāng)然除非你指的是一個(gè)變量名而不是這種編碼本身.

什么編程語言支持 Unicode?

在大約 1993 年之后開發(fā)的大多數(shù)現(xiàn)代編程語言都有一個(gè)特別的數(shù)據(jù)類型, 叫做 Unicode/ISO 10646-1 字符. 在 Ada95 中叫 Wide_Character, 在 Java 中叫 char.

ISO C 也詳細(xì)說明了處理多字節(jié)編碼和寬字符 (wide characters) 的機(jī)制, 1994 年 9 月 Amendment 1 to ISO C 發(fā)表時(shí)又加入了更多. 這些機(jī)制主要是為各類東亞編碼而設(shè)計(jì)的, 它們比處理 UCS 所需的要健壯得多. UTF-8 是 ISO C 標(biāo)準(zhǔn)調(diào)用多字節(jié)字符串的編碼的一個(gè)例子, wchar_t 類型可以用來存放 Unicode 字符.

在 Linux 下該如何使用 Unicode?

在 UTF-8 之前, 不同地區(qū)的 Linux 用戶使用各種各樣的 ASCII 擴(kuò)展. 最普遍的歐洲編碼是 ISO 8859-1 和 ISO 8859-2, 希臘編碼 ISO 8859-7, 俄國編碼 KOI-8, 日本編碼 EUC 和 Shift-JIS, 等等. 這使得 文件的交換非常困難, 且應(yīng)用軟件必須特別關(guān)心這些編碼的不同之處.

最終, Unicode 將取代所有這些編碼, 主要通過 UTF-8 的形式. UTF-8 將應(yīng)用在

  • 文本文件 (源代碼, HTML 文件, email 消息, 等等)
  • 文件名
  • 標(biāo)準(zhǔn)輸入與標(biāo)準(zhǔn)輸出, 管道
  • 環(huán)境變量
  • 剪切與粘貼選擇緩沖區(qū)
  • telnet, modem 和到終端模擬器的串口連接
  • 以及其他地方以前用ASCII來表示的字節(jié)串

在 UTF-8 模式下, 終端模擬器, 比如 xterm 或 Linux console driver, 將每次按鍵轉(zhuǎn)換成相應(yīng)的 UTF-8 串, 然后發(fā)送到前臺(tái)進(jìn)程的 stdin 里. 類似的, 任何進(jìn)程在 stdout 上的輸出都將發(fā)送到終端模擬器, 在那里用一個(gè) UTF-8 解碼器進(jìn)行處理, 之后再用一種 16 位的字體顯示出來.

只有在功能完善的多語言字處理器包里才可能有完全的 Unicode 功能支持. 而廣泛用在 Linux 里用于取代 ASCII 和其他 8 位字符集的方案則要簡(jiǎn)單得多. 第一步, Linux 終端模擬器和命令行工具將只是轉(zhuǎn)變到 UTF-8. 這意味著只用到 級(jí)別1 的 ISO 10646-1 實(shí)現(xiàn) (沒有組合字符), 且只支持那些不需要更多處理的語言象 拉丁, 希臘, 斯拉夫 和許多科學(xué)用符號(hào). 在這個(gè)級(jí)別上, UCS 支持與 ISO 8859 支持類似, 唯一顯著的區(qū)別是現(xiàn)在我們有幾千種字符可以用了, 其中的字符可以用多字節(jié)串來表示.

總有一天 Linux 會(huì)當(dāng)然地支持組合字符, 但即便如此, 對(duì)于組合字符串, 預(yù)作字符(如何可用的話)仍將是首選的. 更正式地, 在 Linux 下用 Unicode 對(duì)文本編碼的首選的方法應(yīng)該是定義在 Unicode Technical Report #15 里的 Normalization Form C.

在今后的一個(gè)階段, 人們可以考慮增加在日文和中文里用到的雙字節(jié)字符的支持 (他們相對(duì)比較簡(jiǎn)單), 組合字符支持, 甚至也許對(duì)從右至左書寫的語言如希伯來文 (他們可不是那么簡(jiǎn)單的) 的支持. 但對(duì)這些高級(jí)功能的支持不應(yīng)該阻礙簡(jiǎn)單的平板 UTF-8 在 拉丁, 希臘, 斯拉夫和科學(xué)用符號(hào)方面的快速應(yīng)用, 以取代大量的歐洲 8 位編碼, 并提供一個(gè)象樣的科學(xué)用符號(hào)集.

我該怎樣修改我的軟件?

有兩種途徑可以支持 UTF-8, 我稱之為軟轉(zhuǎn)換與硬轉(zhuǎn)換. 軟轉(zhuǎn)換時(shí), 各處的數(shù)據(jù)均保存為 UTF-8 形式, 因而需要修改的軟件很少. 在硬轉(zhuǎn)換時(shí), 程序?qū)⒆x入的 UTF-8 數(shù)據(jù)轉(zhuǎn)換成寬字符數(shù)組, 以在應(yīng)用程序內(nèi)部處理. 在輸出時(shí), 再把字符串轉(zhuǎn)換回 UTF-8 形式.

大多數(shù)應(yīng)用程序只用軟轉(zhuǎn)換就可以工作得很好了. 這使得將 UTF-8 引入 Unix 成為切實(shí)可行的. 例如, 象 cat 和 echo 這樣的程序根本不需要修改. 他們?nèi)匀豢梢詫?duì)輸入輸出的是 ISO 8859-2 還是 UTF-8 一無所知, 因?yàn)樗鼈冎皇前徇\(yùn)字節(jié)流而沒有處理它們. 它們只能識(shí)別 ASCII 字符和象 '\n' 這樣的控制碼, 而這在 UTF-8 下也沒有任何改變. 因此, 這些應(yīng)用程序的 UTF-8 編碼與解碼將完全在終端模擬器里完成.

而那些通過數(shù)字節(jié)數(shù)來獲知字符數(shù)量的程序則需要一些小修改. 在 UTF-8 模式下, 它們必須不數(shù)入 0x80 到 0xBF 范圍內(nèi)的字節(jié), 因?yàn)檫@些只是跟隨字節(jié), 它們本身并不是字符. 例如, ls 程序就必須要修改, 因?yàn)樗ㄟ^數(shù)文件名中字符數(shù)來排放給用戶的目錄表格布局. 類似地, 所有的假定其輸出為定寬字體, 并因此而格式化它們的程序, 必須學(xué)會(huì)怎樣數(shù) UTF-8 文本中的字符數(shù). 編輯器的功能, 如刪除單個(gè)字符, 必須要作輕微的修改, 以刪除可能屬于該字符的所有字節(jié). 受影響有編輯器 (vi,emacs, 等等)以及使用 ncurses 庫的程序.

Linux 核心使用軟轉(zhuǎn)換也可以工作得很好, 只需要非常微小的修改以支持 UTF-8. 大多數(shù)處理字符串的核心功能 (例如: 文件名, 環(huán)境變量, 等等) 都不受影響. 下列地方也許必須修改:

  • 控制臺(tái)顯示與鍵盤驅(qū)動(dòng)程序 (另一個(gè) VT100 模擬器) 必須能編碼和解碼 UTF-8, 必須要起碼支持 Unicode 字符集的幾個(gè)子集. 從 Linux 1.2 起這些功能已經(jīng)有了.
  • 外部文件系統(tǒng)驅(qū)動(dòng)程序, 例如 VFAT 和 WinNT 必須轉(zhuǎn)換文件名字符編碼. UTF-8 已經(jīng)加入可用的轉(zhuǎn)換選項(xiàng)的列表里了, 因此 mount 命令必須告訴核心驅(qū)動(dòng)程序用戶進(jìn)程希望看到 UTF-8 文件名. 既然 VFAT 和 WinNT 無論如何至少已經(jīng)用了 Unicode了, 那么 UTF-8 在這里就可以發(fā)揮其優(yōu)勢(shì), 以保證轉(zhuǎn)換中無信息損失.
  • POSIX 系統(tǒng)的 tty 驅(qū)動(dòng)程序支持一種 "cooked" 模式, 有一些原始的行編輯功能. 為了讓字符刪除功能工作正常, stty 必須在 tty 驅(qū)動(dòng)程序里設(shè)置 UTF-8 模式, 因此它就不會(huì)把 0x80 到 0xBF 范圍內(nèi)的跟隨字符也數(shù)進(jìn)去了. Bruno Haible 那里已經(jīng)有了一些 stty 和核心 tty 驅(qū)動(dòng) 程序的 Linux 補(bǔ)丁 了.

C 對(duì) Unicode 和 UTF-8 的支持

從 GNU glibc 2.1 開始, wchar_t 類型已經(jīng)正式定為只存放獨(dú)立于當(dāng)前 locale 的, 32位的 ISO 10646 值. glibc 2.2 開始將完全支持 ISO C 中的多字節(jié)轉(zhuǎn)換函數(shù) (wprintf(),mbstowcs(),等等), 這些函數(shù)可以用于在 wchar_t 和包括 UTF-8 在內(nèi)的任何依賴于 locale 的多字節(jié)編碼間進(jìn)行轉(zhuǎn)換.

例如, 你可以寫

  wprintf(L"Sch鰊e Gre!\n");

然后, 你的軟件將按照你的用戶在環(huán)境變量 LC_CTYPE (例如, en_US.UTF-8de_DE.ISO_8859-1) 中選擇的 locale 所指定的編碼來打印這段文字. 你的編譯器必須運(yùn)行在與該 C 源文件所用編碼相應(yīng)的 locale 中, 在目標(biāo)文件中以上的寬字符串將改為 wchar_t 字符串存儲(chǔ). 在輸出時(shí), 運(yùn)行時(shí)庫將把 wchar_t 字符串轉(zhuǎn)換回與程序執(zhí)行時(shí)的 locale 相應(yīng)的編碼.

注意, 類似這樣的操作:

  char c = L"a"; 

只允許從 U+0000 到 U+007F (7 位 ASCII) 范圍里的字符. 對(duì)于非 ASCII 字符, 不能直接從 wchar_tchar 轉(zhuǎn)換.

現(xiàn)在, 象 readline() 這樣的函數(shù)在 UTF-8 locale 下也能工作了.

怎樣激活 UTF-8 模式?

如果你的應(yīng)用程序既支持 8 位字符集 (ISO 8859-*,KOI-8,等等), 也支持 UTF-8, 那么它必須通過某種方法以得知是否應(yīng)使用 UTF-8 模式. 幸運(yùn)的是, 在未來的幾年里, 人們將只使用 UTF-8, 因此你可以將它作為默認(rèn), 但即使如此, 你還是得既支持傳統(tǒng) 8 位字符集, 也支持 UTF-8.

當(dāng)前的應(yīng)用程序使用許許多多的不同的命令行開關(guān)來激活它們各自的 UTF-8 模式, 例如:

  • xterm 命令行選項(xiàng) "-u8" 和 X resource "XTerm*utf8:1"
  • gnat/gcc 命令行選項(xiàng) "-gnatW8"
  • stty 命令行選項(xiàng) "iutf8"
  • mined 命令行選項(xiàng) "-U"
  • xemacs elisp 包裹 以在 UTF-8 和內(nèi)部使用的 MULE 編碼間轉(zhuǎn)換
  • vim 'fileencoding' 選項(xiàng)
  • less 環(huán)境變量 LESSCHARSET=utf-8

記住每一個(gè)應(yīng)用程序的命令行選項(xiàng)或其他配置方法是非常單調(diào)乏味的, 因此急需某種標(biāo)準(zhǔn)方法.

如果你在你的應(yīng)用程序里使用硬轉(zhuǎn)換, 并使用某種特定的 C 庫函數(shù)來處理外部字符編碼和內(nèi)部使用的 wchar_t 編碼的轉(zhuǎn)換工作, 那么 C 庫會(huì)幫你處理模式切換的問題. 你只需將環(huán)境變量 LC_CTYPE 設(shè)為正確的 locale, 例如, 如果你使用 UTF-8, 那就是en.UTF-8, 而如果是 Latin-1, 并需要英語的轉(zhuǎn)換, 則設(shè)為 en.ISO_8859-1.

然而, 大多數(shù)現(xiàn)存軟件的維護(hù)者選擇用軟轉(zhuǎn)換來代替, 而不使用 libc 的寬字符函數(shù), 不僅因?yàn)樗鼈冞€未得到廣泛應(yīng)用, 還因?yàn)檫@會(huì)使得軟件進(jìn)行大規(guī)模修改. 在這種情況下, 你的應(yīng)用程序必須自己來獲知何時(shí)使用 UTF-8 模式. 一種方式是做以下工作:

按照環(huán)境變量 LC_ALL, LC_CTYPE, LANG 的順序, 尋找第一個(gè)有值的變量. 如果該值包含 UTF-8 子串 (也許是小寫或沒有"-") 則默認(rèn)為 UTF-8 模式 (仍然可以用命令行開關(guān)來重設(shè)), 因?yàn)檫@個(gè)值可靠又恰當(dāng)?shù)刂甘玖?C 庫應(yīng)該使用一種 UTF-8 locale.

提供一個(gè)命令行選項(xiàng) (或者如果是 X 客戶程序則用 X resource 的值) 將仍然是有用的, 可以用來重設(shè)由 LC_CTYPE 等環(huán)境變量指定的默認(rèn)值.

我怎樣才能得到 UTF-8 版本的 xterm?

XFree86 里帶的 xterm 版本最近已經(jīng)由 Thomas E. Dickey 加入了支持 UTF-8 的擴(kuò)展. 使用方法是, 獲取 xterm patch #119 (1999-10-16) 或更新版本, 用 "./configure --enable-wide-chars ; make" 來編譯, 然后用命令行選項(xiàng) -u8 來調(diào)用 xterm, 使它將輸入輸出轉(zhuǎn)換為 UTF-8. 在 UTF-8 模式里使用一個(gè) *-ISO10646-1 字體. 當(dāng)你在 ISO 8859-1 模式里時(shí)也可以使用 *-ISO10646-1 字體, 因?yàn)?ISO 10646-1 字體與 ISO 8859-1 字體是完全向后兼容的.

新的支持 UTF-8 的 xterm 版本, 以及一些 ISO 10646-1 字體, 將被收錄入 XFree86 4.0 版里.

xterm 支持組合字符嗎?

Xterm 當(dāng)前只支持級(jí)別1的 ISO 10646-1, 就是說, 不提供組合字符的支持. 當(dāng)前, 組合字符將被當(dāng)作空格字符對(duì)待. xterm 將來的修訂版很有可能加入某些簡(jiǎn)單的組合字符支持, 就是僅僅將那個(gè)有一個(gè)或多個(gè)組合字符的基字符加粗 (logical OR-ing). 對(duì)于在基線以下的和在小字符上方的重音符來說, 這樣處理的結(jié)果還是可以接受的. 對(duì)于象泰國文字體那樣使用特別設(shè)計(jì)的加粗字符的文字, 這樣處理也能工作的很好. 然而, 對(duì)于某些字體里, 在較高的字符上方組合上的重音符, 特別是對(duì)于 "fixed" 字體族, 產(chǎn)生的結(jié)果就不完全令人滿意了. 因此, 在可用的地方, 應(yīng)該繼續(xù)優(yōu)先使用預(yù)作字符.

xterm 支持半寬與全寬 CJK 字體嗎?

Xterm 當(dāng)前只支持那種所有字形都等寬的 cell-spaced 的字體. 將來的修訂版很有可能為 CJK 語言加入半寬與全寬字符支持, 類似于 kterm 提供的那種. 如果選擇的普通字體是 X×Y 象素大小, 且寬字符模式是打開的, 那么 xterm 會(huì)試圖裝入另外的一個(gè) 2X×Y 象素大小的字體 (同樣的 XLFD, 只是 AVERAGE_WIDTH 屬性的值翻倍). 它會(huì)用這個(gè)字體來顯示所有在 Unicode Technical Report #11 里被分配了East Asian Wide (W)East Asian FullWidth (F) 寬度屬性的 Unicode 字符. 下面這個(gè) C 函數(shù)用來測(cè)試一個(gè) Unicode 字符是否是寬字符并需要用覆蓋兩個(gè)字符單元的字形來顯示:

  /* This function tests, whether the ISO 10646/Unicode character code
   * ucs belongs into the East Asian Wide (W) or East Asian FullWidth
   * (F) category as defined in Unicode Technical Report #11. In this
   * case, the terminal emulator should represent the character using a
   * a glyph from a double-wide font that covers two normal (Latin)
   * character cells. */

  int iswide(int ucs)
  {
    if (ucs < 0x1100)
      return 0;

    return
      (ucs >= 0x1100 && ucs <= 0x115f) || /* Hangul Jamo */
      (ucs >= 0x2e80 && ucs <= 0xa4cf && (ucs & ~0x0011) != 0x300a &&
       ucs != 0x303f) ||                     /* CJK ... Yi */
      (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
      (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
      (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
      (ucs >= 0xff00 && ucs <= 0xff5f) || /* Fullwidth Forms */
      (ucs >= 0xffe0 && ucs <= 0xffe6);
  }

某些 C 庫也提供了函數(shù)

  #include <wchar.h>
  int wcwidth(wchar_t wc);
  int wcswidth(const wchar_t *pwcs, size_t n);

用來測(cè)定該寬字符 wc 或由 pwcs 指向的字符串中的 n 個(gè)寬字符碼 (或者少于 n 個(gè)寬字符碼, 如果在 n 個(gè)寬字符碼之前遇到一個(gè)空寬字符的話) 所要求的列位置的數(shù)量. 這些函數(shù)定義在 Open Group 的 Single UNIX Specification 里. 一個(gè)拉丁/希臘/斯拉夫/等等的字符要求一個(gè)列位置, 一個(gè) CJK 象形文字要求兩個(gè), 而一個(gè)組合字符要求零個(gè).

最終 xterm 是否會(huì)支持從右到左的書寫?

此刻還沒有給 xterm 增加從右到左功能的計(jì)劃. 希伯來與阿拉伯用戶因此不得不靠應(yīng)用程序在將希伯來文與阿拉伯文字符串送到終端前按左方向翻轉(zhuǎn)它們, 換句話說, 雙向處理必須在應(yīng)用程序里完成, 而不是在 xterm 里. 至少, 希伯來與阿拉伯文在預(yù)作字形的可用性的形式上, 以及提示表格上的支持, 比 ISO 8859 要有所改進(jìn). 現(xiàn)在還遠(yuǎn)沒有決定 xterm 是否支持雙向文字以及該怎樣工作. ISO 6429 = ECMA-48Unicode bidi algorithm 都提供了可供選擇的開始點(diǎn). 也可以參考 ECMA Technical
Report TR/53
. Xterm 也不處理阿拉伯文, Hangul 或 印度文本的格式化算法, 而且現(xiàn)在還不太清楚在 VT100 模擬器里處理是否可行和值得, 或者應(yīng)該留給應(yīng)用軟件去處理. 如果你打算在你的應(yīng)用程序里支持雙向文字輸出, 看一下 FriBidi, Dov Grobgeld 的 Unicode 雙向算法的自由實(shí)現(xiàn).

我在哪兒能找到 ISO 10646-1 X11 字體?

在過去的幾個(gè)月里出現(xiàn)了相當(dāng)多的 X11 的 Unicode 字體, 并且還在快速增多.

  • Markus Kuhn 正和其他許多志愿者一起工作于手動(dòng)將舊的 -misc-fixed-*-iso8859-1 字體擴(kuò)展到覆蓋所有的歐洲字符表 (拉丁, 希臘, 斯拉夫, 國際音標(biāo)字母表. 數(shù)學(xué)與技術(shù)符號(hào), 某些字體里甚至有亞美尼亞語, 喬治亞語, 片假名等). 更多信息請(qǐng)參考 Unicode fonts and tools for X11 頁. 這些字體將與 XFree86 一起分發(fā). 例如字體
      -misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso10646-1
    

    (舊的 xterm 的 fixed 缺省字體的一個(gè)擴(kuò)展, 包括超過 3000 個(gè)字符) 已經(jīng)是 XFree86 3.9 snapshot 的一部分了.

  • Markus 也做好了 X11R6.4 distribution 里所有的 Adobe 和 B&H BDF 字體的 ISO 10646 版本. 這些字體已經(jīng)包含了全部 Postscript 字體表 (大約 30 個(gè)額外的字符, 大部分也被 CP1252 MS-Windows 使用, 如 smart quotes, dashes 等), 在 ISO 8859-1 編碼下是沒有的. 它們?cè)?ISO 10646-1 版本里是完全可用的.
  • XFree86 4.0 將攜帶一個(gè)集成的 TrueType 字體引擎, 這使得你的 X 應(yīng)用程序可以將任何 Apple/Microsoft 字體用于 ISO 10646-1 編碼.
  • 將來的 XFree86 版本很有可能從分發(fā)版中去除大多數(shù)舊的 BDF 字體, 取而代之的是 ISO 10646-1 編碼的版本. X 服務(wù)器則會(huì)增加一個(gè)自動(dòng)編碼轉(zhuǎn)換器, 只有當(dāng)舊的 8 位軟件請(qǐng)求一個(gè)類似于 ISO 8859-* 編碼的字體時(shí), 才虛擬地從 ISO 10646-1 字體文件中創(chuàng)建一個(gè)這樣的字體. 現(xiàn)代軟件應(yīng)該優(yōu)先地直接使用 ISO 10646-1 字體編碼.
  • ClearlyU (cu12) 是一個(gè)非常有用的 X11 的 12 點(diǎn)陣, 100 dpi 的 proportional ISO 10646-1 BDF 字體, 包含超過 3700 個(gè)字符, 由 Mark Leisher 提供 (樣例圖象).
  • Roman Czyborra 的 GNU Unicode font 項(xiàng)目工作于收集一個(gè)完整的與免費(fèi)的 8×16/16×16 pixel Unicode 字體. 目前已經(jīng)覆蓋了 34000 個(gè)字符.
  • etl-unicode 是一個(gè) ISO 10646-1 BDF 字體, 由 Primoz Peterlin 提供.

Unicode X11 字體名字以 -ISO10646-1 結(jié)尾. 這個(gè) X 邏輯字體描述器 (X Logical Font Descriptor, XLFD) 的 CHARSET_REGISTRY 和 CHARSET_ENCODING 域里的值已經(jīng)為所有 Unicode 和 ISO 10646-1 的 16 位字體而正式地注冊(cè)了. 每個(gè) *-ISO10646-1 字體都包含了整個(gè) Unicode 字符集里的某幾個(gè)子集, 而用戶必須弄清楚他們選擇的字體覆蓋哪幾個(gè)他們需要的字符子集.

*-ISO10646-1 字體通常也指定一個(gè) DEFAULT_CHAR 值, 指向一個(gè)非 Unicode 字形, 用來表示所有在該字體里不可用的字符 (通常是一個(gè)虛線框, 一個(gè) H 的大小, 位于 0x1F 或 0xFFFE). 這使得用戶至少能知道這兒有一個(gè)不支持的字符. xterm 用的小的定寬字體比如 6x13 等, 將永遠(yuǎn)無法覆蓋所有的 Unicode, 因?yàn)樵S多文字比如日本漢字只能用比歐洲用戶廣泛使用的大的象素尺寸才能表示. 歐洲使用的典型的 Unicode 字體將只包含大約 1000 到 3000 個(gè)字符的子集.

我怎樣才能找出一個(gè) X 字體里有哪些字形?

X 協(xié)議無法讓一個(gè)應(yīng)用程序方便地找出一個(gè) cell-spaced 字體提供哪些字形, 它沒有為字體提供這樣的量度. 因此 Mark LeisherErik van de Poel (Netscape) 指定了一個(gè)新的 _XFREE86_GLYPH_RANGES BDF 屬性, 告訴應(yīng)用程序該 BDF 字體實(shí)現(xiàn)了哪個(gè) Unicode 子集. Mark Leisher 提供了一些樣例代碼以產(chǎn)生并掃描這個(gè)屬性, 而 Xmbdfed 3.9 以及更高版本將自動(dòng)將其加入到由它產(chǎn)生的每個(gè) BDF 文件里.

與 UTF-8 終端模擬器相關(guān)的問題是什么?

VT100 終端模擬器接受 ISO 2022 (=ECMA-35) ESC 序列, 用于在不同的字符集間切換.

UTF-8 在 ISO 2022 的意義里是一個(gè) "其他編碼系統(tǒng)" (參考 ECMA 35 的 15.4 節(jié)). UTF-8 是在 ISO 2022 SS2/SS3/G0/G1/G2/G3 世界之外的, 因此如果你從 ISO 2022 切換到 UTF-8, 所有的 SS2/SS3/G0/G1/G2/G3 狀態(tài)都變得沒有意義了, 直到你離開 UTF-8 并切換回 ISO 2022. UTF-8 是一個(gè)沒有國家的編碼, 也就是一個(gè)自我終結(jié)的短字節(jié)序列完全決定了它代表什么字符, 獨(dú)立于任何國家的切換. G0 與 G1 在 ISO 10646 里與在 ISO 8859-1 里相同, 而 G2/G3 在 ISO 10646 里不存在, 因?yàn)槿魏巫址加泄潭ǖ奈恢? 因而不會(huì)發(fā)聲切換. 在 UTF-8 模式下, 你的終端不會(huì)因?yàn)槟闩既坏匮b入一個(gè)二進(jìn)制文件而切換入一種奇怪圖形字符模式. 這使得一個(gè)終端在 UTF-8 模式下比在 ISO 2022 模式下要健壯得多, 而且因此可以有辦法將終端鎖在 UTF-8 模式里, 而不會(huì)偶然地回到 ISO 2022 世界里.

ISO 2022 標(biāo)準(zhǔn)指定了一系列的 ESC % 序列, 以離開 ISO 2022 世界 (指定其他的編碼系統(tǒng), DOCS), 用于 UTF-8 的許多這樣的序列已經(jīng)注冊(cè)進(jìn)了 ISO 2375 International Register of Coded Character Sets:

  • ESC %G 從 ISO 2022 里激活一個(gè)未指定實(shí)現(xiàn)級(jí)別的 UTF-8 模式且允許再返回 ISO 2022.
  • ESC %@ 從 UTF-8 回到 ISO 2022, 條件是通過 ESC %G 進(jìn)入的 UTF-8
  • ESC %/G 切換進(jìn) UTF-8 級(jí)別 1 且不返回.
  • ESC %/H 切換進(jìn) UTF-8 級(jí)別 2 且不返回.
  • ESC %/I 切換進(jìn) UTF-8 級(jí)別 3 且不返回.

當(dāng)一個(gè)終端模擬器在 UTF-8 模式時(shí), 任何 ISO 2022 逃脫碼序列例如用于切換 G2/G3 等的都被忽略. 一個(gè)在 UTF-8 模式下的終端模擬器唯一會(huì)執(zhí)行的 ISO 2022 序列是 ESC %@ 以從 UTF-8 返回 ISO 2022 方案.

UTF-8 仍然允許你使用象 CSI 這樣的 C1 控制字符, 盡管 UTF-8 也使用 0x80-0x9F 范圍里的字節(jié). 重要的是必須理解在 UTF-8 模式下的終端模擬器必須在執(zhí)行任何控制字符前對(duì)收到的字節(jié)流運(yùn)用 UTF-8 解碼器. C1 字符與其他任何大于 U+007F 的字符一樣需先經(jīng)過 UTF-8 解碼.

已經(jīng)有哪些支持 UTF-8 的應(yīng)用程序了?

  • YuditGaspar Sinai 的自由 X11 Unicode 編輯器
  • Mined 98Thomas Wolff 提供, 是一個(gè)可以處理 UTF-8 的文本編輯器.
  • less 版本 346 或更高, 支持 UTF-8
  • C-Kermit 7.0 在傳輸, 終端, 及文件字符集方面支持 UTF-8.
  • Sam 是 Plan9 的 UTF-8 編輯器, 類似于 vi, 也可用于 Linux 和 Win32. (Plan9 是第一個(gè)完全轉(zhuǎn)向 UTF-8, 將其作為字符編碼的操作系統(tǒng).)
  • 9termMatty Farrow 提供, 是一個(gè) Plan9 操作系統(tǒng)的 Unicode/UTF-8 終端模擬器的 Unix 移植.
  • Wily 是一個(gè) Plan9 Acme 編輯器的 Unix 實(shí)現(xiàn).
  • ucm-0.1Juliusz Chroboczek 的 Unicode 字符映射表, 一個(gè)小工具, 使你可以選中任何一個(gè) Unicode 字符并粘貼進(jìn)你的應(yīng)用程序.

有哪些用于改善 UTF-8 支持的補(bǔ)丁?

Postscript 字形的名字與 UCS 代碼是怎么關(guān)聯(lián)的?

參考 Adobe 的 Unicode and Glyph Names 指南.

X11 的剪切與粘貼工作在 UTF-8 時(shí)是如何完成的?

參考 Juliusz Chroboczek客戶機(jī)間 Unicode 文本的交換 草案, 對(duì) ICCCM 的一個(gè)擴(kuò)充的建議, 用一個(gè)新的可用于屬性類型(property type)和選中(selection)目標(biāo)的原子 UTF8_STRING 來處理 UTF-8 的選中.

現(xiàn)在有沒有用于處理 Unicode 的免費(fèi)的庫?

各種 X widget 對(duì) Unicode 支持的現(xiàn)狀如何?

有什么關(guān)于這個(gè)話題的好的郵件列表?

你確實(shí)應(yīng)該訂閱的是 unicode@unicode.org 郵件列表, 這是發(fā)現(xiàn)標(biāo)準(zhǔn)的作者和其他許多領(lǐng)袖的話語的最好辦法. 訂閱方法是, 用 "subscribe" 作為標(biāo)題, "subscribe YOUR@EMAIL.ADDRESS unicode" 作為正文, 發(fā)一條消息到 unicode-request@unicode.org.

也有一個(gè)專注與改進(jìn)通常用于 GNU/Linux 系統(tǒng)上應(yīng)用程序的 UTF-8 支持的郵件列表 linux-utf8@nl.linux.org. 訂閱方法是, 以 "subscribe linux-utf8" 為內(nèi)容, 發(fā)送消息到 majordomo@nl.linux.org. 你也可以瀏覽 linux-utf8 archive

其他相關(guān)的還有 XFree86 組的 "字體" 與 "i18n" 列表, 但你必須成為一名正式的開發(fā)者才能訂閱.

更多參考

我不斷地將新的材料加入這份文檔, 因此請(qǐng)定期來查看. 歡迎所有關(guān)于改進(jìn)的建議, 以及自由軟件社區(qū)里關(guān)于改善 UTF-8 支持的廣告. UTF-8 用在 Linux 里是新近的事, 因此我們?cè)趯淼膸讉€(gè)月里可以見到大量的進(jìn)展.

特別感謝 Ulrich Drepper 和 Bruno Haible 的有價(jià)值的注解

Markus Kuhn <<Markus.Kuhn@cl.cam.ac.uk>
創(chuàng)建于 1999-06-04 -- 最近更新于 2000-01-15 -- http://www.cl.cam.ac.uk/~mgk25/unicode.html



]]>
Java安全策略 摘自《計(jì)算機(jī)世界》http://www.aygfsteel.com/snoics/articles/15538.htmlsnoicssnoicsFri, 14 Oct 2005 09:48:00 GMThttp://www.aygfsteel.com/snoics/articles/15538.htmlhttp://www.aygfsteel.com/snoics/comments/15538.htmlhttp://www.aygfsteel.com/snoics/articles/15538.html#Feedback0http://www.aygfsteel.com/snoics/comments/commentRss/15538.htmlhttp://www.aygfsteel.com/snoics/services/trackbacks/15538.html一、Java中安全策略的概念
----Java應(yīng)用程序環(huán)境的安全策略,詳細(xì)說明了對(duì)于不同的代碼所擁有的不同資源的許可,它由一個(gè)Policy對(duì)象來表達(dá)。為了讓applet(或者運(yùn)行在 SecurityManager下的一個(gè)應(yīng)用程序)能夠執(zhí)行受保護(hù)的行為,例如讀寫文件,applet(或 Java應(yīng)用程序)必須獲得那項(xiàng)操作的許可,安全策略文件就是用來實(shí)現(xiàn)這些許可。
----Policy對(duì)象可能有多個(gè)實(shí)體,雖然任何時(shí)候只能有一個(gè)起作用。當(dāng)前安裝的Policy對(duì)象,在程序中可以通過調(diào)用getPolicy方法得到,也可以通過調(diào)用setPolicy方法改變。Policy對(duì)象評(píng)估整個(gè)策略,返回一個(gè)適當(dāng)?shù)腜ermissions對(duì)象,詳細(xì)說明哪些代碼可以訪問哪些資源。

---- 策略文件可以儲(chǔ)存在無格式的ASCII文件或Policy類的二進(jìn)制文件或數(shù)據(jù)庫中。本文僅討論無格式的ASCII文件的形式。

二、Policy文件的格式
----為了能夠更好地理解下面的內(nèi)容,建議在閱讀時(shí)參照 \jdk1.2\jre\lib\security\java.policy文件和\jdk1.2\jre\lib\security\java.security文件的內(nèi)容。
----Policy文件的語法格式與說明

----一個(gè)Policy文件實(shí)質(zhì)上是一個(gè)記錄列表,它可能含有一個(gè) “keystore”記錄,以及含有零個(gè)或多個(gè)“grant”記錄。其格式如下:

keystore “some_keystore_url", “keystore_type";

grant [ SignedBy “signer_names" ] [ , CodeBase “URL" ] {
Permission permission_class_name [ “target_name" ]
[ , “action"] [, SignedBy “signer_names" ];
Permission ...
};

----(1)“keystore"記錄

----一個(gè)keystore是一個(gè)私有密鑰(private keys)數(shù)據(jù)庫和相應(yīng)的數(shù)字簽名,例如X.509證書。Policy文件中可能只有一條keystore記錄(也可能不含有該記錄),它可以出現(xiàn)在文件中g(shù)rant記錄以外的任何地方。Policy配置文件中指定的 keystores用于尋找grant記錄中指定的、簽名者的公共密鑰(public keys),如果任何grant 記錄指定簽名者(signer_names),那么,keystore記錄必須出現(xiàn)在policy配置文件中。

----“some_keystore_url"是指keystore的URL位置, “keystore_type"是指keystore的類型。第二個(gè)選項(xiàng)是可選項(xiàng),如果沒有指定,該類型則假定由安全屬性文件(java.security)中的“keystore.type"屬性來確定。keystore類型定義了 keystore信息的存儲(chǔ)和數(shù)據(jù)格式,用于保護(hù)keystore中的私有密鑰和keystore完整性的算法。 Sun Microsystems支持的缺省類型為“JKS”。

---- (2)“grant"記錄

----在Policy文件中的每一個(gè)grant記錄含有一個(gè)CodeSource (一個(gè)指定的代碼)及其permission(許可)。

----Policy文件中的每一條grant記錄遵循下面的格式,以保留字“grant”開頭,表示一條新的記錄的開始,“Permission”是另一個(gè)保留字,在記錄中用來標(biāo)記一個(gè)新的許可的開始。每一個(gè)grant記錄授予一個(gè)指定的代碼(CodeBase)、一套許可(Permissions)。

----permission_class_name必須是一個(gè)合格并存在的類名,例如java.io.FilePermission,不能使用縮寫(例如,F(xiàn)ilePermission)。

----target_name用來指定目標(biāo)類的位置,action用于指定目標(biāo)類擁有的權(quán)限。

----target_name可以直接指定類名(可以是絕對(duì)或相對(duì)路徑)、目錄名,也可以是下面的通配符:

directory/* 目錄下的所有文件
* 當(dāng)前目錄的所有文件
directory/- 目錄下的所有文件,包括子目錄
- 當(dāng)前目錄下的所有文件,包括子目錄
<< ALL FILES >>文件系統(tǒng)中的所有文件

----對(duì)于java.io.FilePermission,action可以是:read, write, delete和execute。

----對(duì)于java.net.SocketPermission,action可以是:listen, accept,connect,read,write。

---- (3)Policy文件中的屬性擴(kuò)展(Property Expansion)屬性擴(kuò)展與shell中使用的變量擴(kuò)展類似,它的格式為:
“${some.property}"

----實(shí)際使用的例子為:
permission java.io.FilePermission
“${user.home}", “read";

----“${user.home}"的值為“d:\Project",因此,下面的語句和上面的語句是一樣的:
permission java.io.FilePermission “d:\Project ", “read";

三、實(shí) 例
----當(dāng)初始化Policy時(shí),首先裝載系統(tǒng)Policy,然后再增加用戶Policy,如果兩者都不存在,則使用缺省的Policy,即原始的沙箱模型。
----系統(tǒng)Policy文件的缺省位置為:
{java.home}/lib/security/java.policy (Solaris)
{java.home}\lib\security\java.policy (Windows)

----用戶Policy文件的缺省位置為:
{user.home}/.java.policy (Solaris)
{user.home}\.java.policy (Windows)

----其實(shí),在實(shí)際使用中,我們可能不會(huì)像上面介紹的那么復(fù)雜,特別是在不使用數(shù)字簽名時(shí)。這時(shí),我們完全可以借鑒JDK 1.2提供給我們的現(xiàn)成的 \jdk1.2\jre\lib\security\java.policy文件,根據(jù)我們的需要做相應(yīng)的修改,本文就針對(duì)不使用數(shù)字簽名情況詳細(xì)說明安全策略文件的用法。

----下面,是一個(gè)完整的在Windows 95/98/NT下使用的.java.policy文件。在文件中,分別使用注釋的形式說明了每個(gè)“permission”記錄的用途。

// For LanServerTalk.java and LanClientTalk.java

grant {
//對(duì)系統(tǒng)和用戶目錄“讀”的權(quán)限
permission java.util.PropertyPermission “user.dir", “read";
permission java.util.PropertyPermission “user.home", “read";
permission java.util.PropertyPermission “java.home", “read";
permission java.util.PropertyPermission “java.class.path", “read";
permission java.util.PropertyPermission “user.name", “read";

//對(duì)線程和線程組的操作權(quán)限
permission java.lang.RuntimePermission “modifyThread";
permission java.lang.RuntimePermission “modifyThreadGroup";

//操作Socket端口的各種權(quán)限
permission java.net.SocketPermission “-", “l(fā)isten";
permission java.net.SocketPermission “-", “accept";
permission java.net.SocketPermission “-", “connect";
permission java.net.SocketPermission “-", “read";
permission java.net.SocketPermission “-", “write";

//讀寫文件的權(quán)限
permission java.io.FilePermission “-", “read";
permission java.io.FilePermission “-", “write";

//退出系統(tǒng)的權(quán)限,例如System.exit(0)
permission java.lang.RuntimePermission “exitVM";
};

四、.Java.policy文件的使用
---- 對(duì)于Windows 95/98/NT,使用.Java.policy文件的方法主要有下面兩種。
----1. 使用缺省目錄

---- 我們可以簡(jiǎn)單地將編輯好的.Java.policy文件拷貝到 Windows 95/98/NT的HOME目錄,這時(shí),所有的applet(或Java應(yīng)用程序)可能都擁有某些相同的權(quán)限,使用起來簡(jiǎn)單,但不靈活(例如:對(duì)于Java.io.FilePermission ,其目標(biāo)類的 target_name必須使用絕對(duì)路徑),如果不是在企業(yè)內(nèi)部網(wǎng)中使用,還可能存在一定安全隱患。

---- 2. 在命令行中指定

---- 在命令行,如果我們希望傳遞一個(gè)Policy文件給 appletviewer,還可以使用“-J-Djava.security.policy"參數(shù)來指定policy的位置:

appletviewer -J-Djava.security.policy=pURL myApplet

----pURL為Policy文件的位置。下面,是一個(gè)實(shí)際的例子,以當(dāng)前目錄的.java.policy文件所指定的安全策略運(yùn)行當(dāng)前目錄的LanServerTalk.html(文件中裝載并運(yùn)行LanServerTalk.Java):

appletviewer -J-Djava.security.policy
=.Java.policy LanServerTalk.html

----這種方法使用靈活,特別是作為一個(gè)軟件包在企業(yè)內(nèi)部網(wǎng)中發(fā)布時(shí),安裝、設(shè)置和遷移軟件,基本無須修改Policy文件的內(nèi)容,使用起來相當(dāng)簡(jiǎn)單,而且,安全許可的范圍控制較精細(xì)。

摘自《計(jì)算機(jī)世界》


snoics 2005-10-14 17:48 發(fā)表評(píng)論
]]>
JAVA面試題集 [轉(zhuǎn)]http://www.aygfsteel.com/snoics/articles/15489.htmlsnoicssnoicsFri, 14 Oct 2005 02:15:00 GMThttp://www.aygfsteel.com/snoics/articles/15489.htmlhttp://www.aygfsteel.com/snoics/comments/15489.htmlhttp://www.aygfsteel.com/snoics/articles/15489.html#Feedback0http://www.aygfsteel.com/snoics/comments/commentRss/15489.htmlhttp://www.aygfsteel.com/snoics/services/trackbacks/15489.html閱讀全文

snoics 2005-10-14 10:15 發(fā)表評(píng)論
]]>
正則表達(dá)式簡(jiǎn)介 [轉(zhuǎn)]http://www.aygfsteel.com/snoics/articles/15059.htmlsnoicssnoicsSun, 09 Oct 2005 07:01:00 GMThttp://www.aygfsteel.com/snoics/articles/15059.htmlhttp://www.aygfsteel.com/snoics/comments/15059.htmlhttp://www.aygfsteel.com/snoics/articles/15059.html#Feedback0http://www.aygfsteel.com/snoics/comments/commentRss/15059.htmlhttp://www.aygfsteel.com/snoics/services/trackbacks/15059.html【javascript】在javascript中使用正則表達(dá)式- -

這些頁包含的信息其目的是提供一個(gè)關(guān)于正則表達(dá)式的通用介紹。

 盡管試圖讓每個(gè)主題的內(nèi)容都比較獨(dú)立,但這些主題所包含的大部分信息都依賴于對(duì)前面所介紹的特性或概念的理解。因此,建議您順序地仔細(xì)閱讀這些主題,以便最全面地了解這些材料。

“正則表達(dá)式簡(jiǎn)介”包括下述各個(gè)主題:

正則表達(dá)式

早期起源

使用正則表達(dá)式

正則表達(dá)式語法

建立正則表達(dá)式

優(yōu)先權(quán)順序

普通字符

特殊字符

非打印字符

字符匹配

限定符

定位符

選擇與編組

后向引用

正則表達(dá)式

如果原來沒有使用過正則表達(dá)式,那么可能對(duì)這個(gè)術(shù)語和概念會(huì)不太熟悉。不過,它們并不是您想象的那么新奇。

請(qǐng)回想一下在硬盤上是如何查找文件的。您肯定會(huì)使用 ? 和 * 字符來幫助查找您正尋找的文件。? 字符匹配文件名中的單個(gè)字符,而 * 則匹配一個(gè)或多個(gè)字符。一個(gè)如 'data?.dat' 的模式可以找到下述文件:

data1.dat

data2.dat

datax.dat

dataN.dat

如果使用 * 字符代替 ? 字符,則將擴(kuò)大找到的文件數(shù)量。'data*.dat' 可以匹配下述所有文件名:

data.dat

data1.dat

data2.dat

data12.dat

datax.dat

dataXYZ.dat

盡管這種搜索文件的方法肯定很有用,但也十分有限。? 和 * 通配符的有限能力可以使你對(duì)正則表達(dá)式能做什么有一個(gè)概念,不過正則表達(dá)式的功能更強(qiáng)大,也更靈活。

早期起源

正則表達(dá)式的“祖先”可以一直上溯至對(duì)人類神經(jīng)系統(tǒng)如何工作的早期研究。Warren McCulloch 和 Walter Pitts 這兩位神經(jīng)生理學(xué)家研究出一種數(shù)學(xué)方式來描述這些神經(jīng)網(wǎng)絡(luò)。

1956 年, 一位叫 Stephen Kleene 的美國數(shù)學(xué)家在 McCulloch 和 Pitts 早期工作的基礎(chǔ)上,發(fā)表了一篇標(biāo)題為“神經(jīng)網(wǎng)事件的表示法”的論文,引入了正則表達(dá)式的概念。正則表達(dá)式就是用來描述他稱為“正則集的代數(shù)”的表達(dá)式,因此采用“正則表達(dá)式”這個(gè)術(shù)語。

隨后,發(fā)現(xiàn)可以將這一工作應(yīng)用于使用Ken Thompson 的計(jì)算搜索算法的一些早期研究,Ken Thompson是Unix 的主要發(fā)明人。正則表達(dá)式的第一個(gè)實(shí)用應(yīng)用程序就是 Unix 中的qed 編輯器。

如他們所說,剩下的就是眾所周知的歷史了。從那時(shí)起直至現(xiàn)在正則表達(dá)式都是基于文本的編輯器和搜索工具中的一個(gè)重要部分。

使用正則表達(dá)式

在典型的搜索和替換操作中,必須提供要查找的確切文字。這種技術(shù)對(duì)于靜態(tài)文本中的簡(jiǎn)單搜索和替換任務(wù)可能足夠了,但是由于它缺乏靈活性,因此在搜索動(dòng)態(tài)文本時(shí)就有困難了,甚至是不可能的。

使用正則表達(dá)式,就可以:

  • 測(cè)試字符串的某個(gè)模式。例如,可以對(duì)一個(gè)輸入字符串進(jìn)行測(cè)試,看在該字符串是否存在一個(gè)電話號(hào)碼模式或一個(gè)信用卡號(hào)碼模式。這稱為數(shù)據(jù)有效性驗(yàn)證。
  • 替換文本??梢栽谖臋n中使用一個(gè)正則表達(dá)式來標(biāo)識(shí)特定文字,然后可以全部將其刪除,或者替換為別的文字。
  • 根據(jù)模式匹配從字符串中提取一個(gè)子字符串。可以用來在文本或輸入字段中查找特定文字。

例如,如果需要搜索整個(gè) web 站點(diǎn)來刪除某些過時(shí)的材料并替換某些HTML 格式化標(biāo)記,則可以使用正則表達(dá)式對(duì)每個(gè)文件進(jìn)行測(cè)試,看在該文件中是否存在所要查找的材料或 HTML 格式化標(biāo)記。用這個(gè)方法,就可以將受影響的文件范圍縮小到包含要?jiǎng)h除或更改的材料的那些文件。然后可以使用正則表達(dá)式來刪除過時(shí)的材料,最后,可以再次使用正則表達(dá)式來查找并替換那些需要替換的標(biāo)記。

另一個(gè)說明正則表達(dá)式非常有用的示例是一種其字符串處理能力還不為人所知的語言。VBScript 是 Visual Basic 的一個(gè)子集,具有豐富的字符串處理功能。與 C 類似的 Jscript 則沒有這一能力。正則表達(dá)式給 JScript 的字符串處理能力帶來了明顯改善。不過,可能還是在 VBScript 中使用正則表達(dá)式的效率更高,它允許在單個(gè)表達(dá)式中執(zhí)行多個(gè)字符串操作。

正則表達(dá)式語法

一個(gè)正則表達(dá)式就是由普通字符(例如字符 a 到 z)以及特殊字符(稱為元字符)組成的文字模式。該模式描述在查找文字主體時(shí)待匹配的一個(gè)或多個(gè)字符串。正則表達(dá)式作為一個(gè)模板,將某個(gè)字符模式與所搜索的字符串進(jìn)行匹配。

這里有一些可能會(huì)遇到的正則表達(dá)式示例:

JScript VBScript 匹配
/^\[ \t]*$/ "^\[ \t]*$" 匹配一個(gè)空白行。
/\d{2}-\d{5}/ "\d{2}-\d{5}" 驗(yàn)證一個(gè)ID 號(hào)碼是否由一個(gè)2位數(shù)字,一個(gè)連字符以及一個(gè)5位數(shù)字組成。
/<(.*)>.*<\/\1>/ "<(.*)>.*<\/\1>" 匹配一個(gè) HTML 標(biāo)記。

 

下表是元字符及其在正則表達(dá)式上下文中的行為的一個(gè)完整列表:

字符 描述
\ 將下一個(gè)字符標(biāo)記為一個(gè)特殊字符、或一個(gè)原義字符、或一個(gè) 后向引用、或一個(gè)八進(jìn)制轉(zhuǎn)義符。例如,'n' 匹配字符 "n"。'\n' 匹配一個(gè)換行符。序列 '\\' 匹配 "\" 而 "\(" 則匹配 "("。
^ 匹配輸入字符串的開始位置。如果設(shè)置了 RegExp 對(duì)象的 Multiline 屬性,^ 也匹配 '\n' 或 '\r' 之后的位置。
$ 匹配輸入字符串的結(jié)束位置。如果設(shè)置了RegExp 對(duì)象的 Multiline 屬性,$ 也匹配 '\n' 或 '\r' 之前的位置。
* 匹配前面的子表達(dá)式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。 * 等價(jià)于{0,}。
+ 匹配前面的子表達(dá)式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等價(jià)于 {1,}。
? 匹配前面的子表達(dá)式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等價(jià)于 {0,1}。
{n} n 是一個(gè)非負(fù)整數(shù)。匹配確定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的兩個(gè) o。
{n,} n 是一個(gè)非負(fù)整數(shù)。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等價(jià)于 'o+'。'o{0,}' 則等價(jià)于 'o*'。
{n,m} mn 均為非負(fù)整數(shù),其中n <= m。最少匹配 n 次且最多匹配 m 次。劉, "o{1,3}" 將匹配 "fooooood" 中的前三個(gè) o。'o{0,1}' 等價(jià)于 'o?'。請(qǐng)注意在逗號(hào)和兩個(gè)數(shù)之間不能有空格。
? 當(dāng)該字符緊跟在任何一個(gè)其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面時(shí),匹配模式是非貪婪的。非貪婪模式盡可能少的匹配所搜索的字符串,而默認(rèn)的貪婪模式則盡可能多的匹配所搜索的字符串。例如,對(duì)于字符串 "oooo",'o+?' 將匹配單個(gè) "o",而 'o+' 將匹配所有 'o'。
. 匹配除 "\n" 之外的任何單個(gè)字符。要匹配包括 '\n' 在內(nèi)的任何字符,請(qǐng)使用象 '[.\n]' 的模式。
(pattern) 匹配pattern 并獲取這一匹配。所獲取的匹配可以從產(chǎn)生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中則使用 $0$9 屬性。要匹配圓括號(hào)字符,請(qǐng)使用 '\(' 或 '\)'。
(?:pattern) 匹配 pattern 但不獲取匹配結(jié)果,也就是說這是一個(gè)非獲取匹配,不進(jìn)行存儲(chǔ)供以后使用。這在使用 "或" 字符 (|) 來組合一個(gè)模式的各個(gè)部分是很有用。例如, 'industr(?:y|ies) 就是一個(gè)比 'industry|industries' 更簡(jiǎn)略的表達(dá)式。
(?=pattern) 正向預(yù)查,在任何匹配 pattern 的字符串開始處匹配查找字符串。這是一個(gè)非獲取匹配,也就是說,該匹配不需要獲取供以后使用。例如, 'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。預(yù)查不消耗字符,也就是說,在一個(gè)匹配發(fā)生后,在最后一次匹配之后立即開始下一次匹配的搜索,而不是從包含預(yù)查的字符之后開始。
(?!pattern) 負(fù)向預(yù)查,在任何不匹配Negative lookahead matches the search string at any point where a string not matching pattern 的字符串開始處匹配查找字符串。這是一個(gè)非獲取匹配,也就是說,該匹配不需要獲取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。預(yù)查不消耗字符,也就是說,在一個(gè)匹配發(fā)生后,在最后一次匹配之后立即開始下一次匹配的搜索,而不是從包含預(yù)查的字符之后開始
x|y 匹配 xy。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 則匹配 "zood" 或 "food"。
[xyz] 字符集合。匹配所包含的任意一個(gè)字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。
[^xyz] 負(fù)值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain" 中的'p'。
[a-z] 字符范圍。匹配指定范圍內(nèi)的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z' 范圍內(nèi)的任意小寫字母字符。
[^a-z] 負(fù)值字符范圍。匹配任何不在指定范圍內(nèi)的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到 'z' 范圍內(nèi)的任意字符。
\b 匹配一個(gè)單詞邊界,也就是指單詞和空格間的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
\B 匹配非單詞邊界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
\cx 匹配由x指明的控制字符。例如, \cM 匹配一個(gè) Control-M 或回車符。 x 的值必須為 A-Z 或 a-z 之一。否則,將 c 視為一個(gè)原義的 'c' 字符。
\d 匹配一個(gè)數(shù)字字符。等價(jià)于 [0-9]。
\D 匹配一個(gè)非數(shù)字字符。等價(jià)于 [^0-9]。
\f 匹配一個(gè)換頁符。等價(jià)于 \x0c 和 \cL。
\n 匹配一個(gè)換行符。等價(jià)于 \x0a 和 \cJ。
\r 匹配一個(gè)回車符。等價(jià)于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、換頁符等等。等價(jià)于 [ \f\n\r\t\v]。
\S 匹配任何非空白字符。等價(jià)于 [^ \f\n\r\t\v]。
\t 匹配一個(gè)制表符。等價(jià)于 \x09 和 \cI。
\v 匹配一個(gè)垂直制表符。等價(jià)于 \x0b 和 \cK。
\w 匹配包括下劃線的任何單詞字符。等價(jià)于'[A-Za-z0-9_]'。
\W 匹配任何非單詞字符。等價(jià)于 '[^A-Za-z0-9_]'。
\xn 匹配 n,其中 n 為十六進(jìn)制轉(zhuǎn)義值。十六進(jìn)制轉(zhuǎn)義值必須為確定的兩個(gè)數(shù)字長(zhǎng)。例如, '\x41' 匹配 "A"。'\x041' 則等價(jià)于 '\x04' & "1"。正則表達(dá)式中可以使用 ASCII 編碼。.
\num 匹配 num,其中 num 是一個(gè)正整數(shù)。對(duì)所獲取的匹配的引用。例如,'(.)\1' 匹配兩個(gè)連續(xù)的相同字符。
\n 標(biāo)識(shí)一個(gè)八進(jìn)制轉(zhuǎn)義值或一個(gè)后向引用。如果 \n 之前至少 n 個(gè)獲取的子表達(dá)式,則 n 為后向引用。否則,如果 n 為八進(jìn)制數(shù)字 (0-7),則 n 為一個(gè)八進(jìn)制轉(zhuǎn)義值。
\nm 標(biāo)識(shí)一個(gè)八進(jìn)制轉(zhuǎn)義值或一個(gè)后向引用。如果 \nm 之前至少有is preceded by at least nm 個(gè)獲取得子表達(dá)式,則 nm 為后向引用。如果 \nm 之前至少有 n 個(gè)獲取,則 n 為一個(gè)后跟文字 m 的后向引用。如果前面的條件都不滿足,若  nm 均為八進(jìn)制數(shù)字 (0-7),則 \nm 將匹配八進(jìn)制轉(zhuǎn)義值 nm。
\nml 如果 n 為八進(jìn)制數(shù)字 (0-3),且 ml 均為八進(jìn)制數(shù)字 (0-7),則匹配八進(jìn)制轉(zhuǎn)義值 nml。
\un 匹配 n,其中 n 是一個(gè)用四個(gè)十六進(jìn)制數(shù)字表示的 Unicode 字符。例如, \u00A9 匹配版權(quán)符號(hào) (?)。

建立正則表達(dá)式

構(gòu)造正則表達(dá)式的方法和創(chuàng)建數(shù)學(xué)表達(dá)式的方法一樣。也就是用多種元字符與操作符將小的表達(dá)式結(jié)合在一起來創(chuàng)建更大的表達(dá)式。

可以通過在一對(duì)分隔符之間放入表達(dá)式模式的各種組件來構(gòu)造一個(gè)正則表達(dá)式。對(duì) JScript 而言,分隔符為一對(duì)正斜杠 (/) 字符。例如:

/expression/

對(duì) VBScript 而言,則采用一對(duì)引號(hào) ("") 來確定正則表達(dá)式的邊界。例如:

"expression"

在上面所示的兩個(gè)示例中,正則表達(dá)式模式 (expression) 均存儲(chǔ)在RegExp 對(duì)象的Pattern 屬性中。

正則表達(dá)式的組件可以是單個(gè)的字符、字符集合、字符范圍、字符間的選擇或者所有這些組件的任意組合。

優(yōu)先權(quán)順序

在構(gòu)造正則表達(dá)式之后,就可以象數(shù)學(xué)表達(dá)式一樣來求值,也就是說,可以從左至右并按照一個(gè)優(yōu)先權(quán)順序來求值。

下表從最高優(yōu)先級(jí)到最低優(yōu)先級(jí)列出各種正則表達(dá)式操作符的優(yōu)先權(quán)順序:

操作符 描述
\ 轉(zhuǎn)義符
(), (?:), (?=), [] 圓括號(hào)和方括號(hào)
*, +, ?, {n}, {n,}, {n,m} 限定符
^, $, \anymetacharacter 位置和順序
| “或”操作

普通字符

普通字符由所有那些未顯式指定為元字符的打印和非打印字符組成。這包括所有的大寫和小寫字母字符,所有數(shù)字,所有標(biāo)點(diǎn)符號(hào)以及一些符號(hào)。

最簡(jiǎn)單的正則表達(dá)式是一個(gè)單獨(dú)的普通字符,可以匹配所搜索字符串中的該字符本身。例如,單字符模式 'A' 可以匹配所搜索字符串中任何位置出現(xiàn)的字母 'A'。這里有一些單字符正則表達(dá)式模式的示例:

/a/
/7/
/M/

等價(jià)的 VBScript 單字符正則表達(dá)式為:

"a"
"7"
"M"

可以將多個(gè)單字符組合在一起得到一個(gè)較大的表達(dá)式。例如,下面的 JScript 正則表達(dá)式不是別的,就是通過組合單字符表達(dá)式 'a'、'7'以及 'M' 所創(chuàng)建出來的一個(gè)表達(dá)式。

/a7M/

等價(jià)的 VBScript 表達(dá)式為:

"a7M"

請(qǐng)注意這里沒有連接操作符。所需要做的就是將一個(gè)字符放在了另一個(gè)字符后面。

特殊字符

有不少元字符在試圖對(duì)其進(jìn)行匹配時(shí)需要進(jìn)行特殊的處理。要匹配這些特殊字符,必須首先將這些字符轉(zhuǎn)義,也就是在前面使用一個(gè)反斜杠 (\)。下表給出了這些特殊字符及其含義:

特殊字符 說明
$ 匹配輸入字符串的結(jié)尾位置。如果設(shè)置了 RegExp 對(duì)象的 Multiline 屬性,則 $ 也匹配 '\n' 或 '\r'。要匹配 $ 字符本身,請(qǐng)使用 \$。
( ) 標(biāo)記一個(gè)子表達(dá)式的開始和結(jié)束位置。子表達(dá)式可以獲取供以后使用。要匹配這些字符,請(qǐng)使用 \( 和 \)。
* 匹配前面的子表達(dá)式零次或多次。要匹配 * 字符,請(qǐng)使用 \*。
+ 匹配前面的子表達(dá)式一次或多次。要匹配 + 字符,請(qǐng)使用 \+。
. 匹配除換行符 \n之外的任何單字符。要匹配 .,請(qǐng)使用 \。
[ 標(biāo)記一個(gè)中括號(hào)表達(dá)式的開始。要匹配 [,請(qǐng)使用 \[。
? 匹配前面的子表達(dá)式零次或一次,或指明一個(gè)非貪婪限定符。要匹配 ? 字符,請(qǐng)使用 \?。
\ 將下一個(gè)字符標(biāo)記為或特殊字符、或原義字符、或后向引用、或八進(jìn)制轉(zhuǎn)義符。例如, 'n' 匹配字符 'n'。'\n' 匹配換行符。序列 '\\' 匹配 "\",而 '\(' 則匹配 "("。
^ 匹配輸入字符串的開始位置,除非在方括號(hào)表達(dá)式中使用,此時(shí)它表示不接受該字符集合。要匹配 ^ 字符本身,請(qǐng)使用 \^。
{ 標(biāo)記限定符表達(dá)式的開始。要匹配 {,請(qǐng)使用 \{。
| 指明兩項(xiàng)之間的一個(gè)選擇。要匹配 |,請(qǐng)使用 \|。

非打印字符

有不少很有用的非打印字符,偶爾必須使用。下表顯示了用來表示這些非打印字符的轉(zhuǎn)義序列:

字符 含義
\cx 匹配由x指明的控制字符。例如, \cM 匹配一個(gè) Control-M 或回車符。 x 的值必須為 A-Z 或 a-z 之一。否則,將 c 視為一個(gè)原義的 'c' 字符。
\f 匹配一個(gè)換頁符。等價(jià)于 \x0c 和 \cL。
\n 匹配一個(gè)換行符。等價(jià)于 \x0a 和 \cJ。
\r 匹配一個(gè)回車符。等價(jià)于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、換頁符等等。等價(jià)于 [ \f\n\r\t\v]。
\S 匹配任何非空白字符。等價(jià)于 [^ \f\n\r\t\v]。
\t 匹配一個(gè)制表符。等價(jià)于 \x09 和 \cI。
\v 匹配一個(gè)垂直制表符。等價(jià)于 \x0b 和 \cK。

字符匹配

句點(diǎn) (.) 匹配一個(gè)字符串中任何單個(gè)的打印或非打印字符,除了換行符 (\n) 之外。下面的 JScript 正則表達(dá)式可以匹配 'aac'、'abc'、'acc'、'adc'如此等等,同樣也可以匹配 'a1c'、'a2c'、a-c'以及 a#c':

/a.c/

等價(jià)的 VBScript 正則表達(dá)式為:

"a.c"

如果試圖匹配一個(gè)包含文件名的字符串,其中句點(diǎn) (.) 是輸入字符串的一部分,則可以在正則表達(dá)式中的句點(diǎn)前面加上一個(gè)反斜杠 (\) 字符來實(shí)現(xiàn)這一要求。舉例來說,下面的 JScript 正則表達(dá)式就能匹配 'filename.ext':

/filename\.ext/

對(duì) VBScript 而言,等價(jià)的表達(dá)式如下所示:

"filename\.ext"

這些表達(dá)式仍然是相當(dāng)有限的。它們只允許匹配任何單字符。很多情況下,對(duì)從列表中匹配特殊字符十分有用。例如,如果輸入文字中包含用數(shù)字表示為Chapter 1, Chapter 2諸如此類的章節(jié)標(biāo)題,你可能需要找到這些章節(jié)標(biāo)題。

括號(hào)表達(dá)式

可以在一個(gè)方括號(hào) ([ 和 ]) 中放入一個(gè)或多個(gè)單字符,來創(chuàng)建一個(gè)待匹配的列表。如果字符被放入括號(hào)中括起來,則該列表稱為括號(hào)表達(dá)式。括號(hào)內(nèi)和其他任何地方一樣,普通字符代表其本身,也就是說,它們匹配輸入文字中出現(xiàn)的一處自己。大多數(shù)特殊字符在位于括號(hào)表達(dá)式中時(shí)都將失去其含義。這里有一些例外:

  • ']' 字符如果不是第一項(xiàng),則將結(jié)束一個(gè)列表。要在列表中匹配 ']' 字符,請(qǐng)將其放在第一項(xiàng),緊跟在開始的 '[' 后面。
  • '\' 仍然作為轉(zhuǎn)義符。要匹配 '\' 字符,請(qǐng)使用 '\\'。

括號(hào)表達(dá)式中所包含的字符只匹配該括號(hào)表達(dá)式在正則表達(dá)式中所處位置的一個(gè)單字符。下面的 JScript 正則表達(dá)式可以匹配 'Chapter 1'、'Chapter 2'、'Chapter 3'、'Chapter 4' 以及 'Chapter 5':

/Chapter [12345]/

在 VBScript 中要匹配同樣的章節(jié)標(biāo)題,請(qǐng)使用下面的表達(dá)式:

"Chapter [12345]"

請(qǐng)注意單詞 'Chapter' 及后面的空格與括號(hào)內(nèi)的字符的位置關(guān)系是固定的。因此,括號(hào)表達(dá)式只用來指定滿足緊跟在單詞 'Chapter' 和一個(gè)空格之后的單字符位置的字符集合。這里是第九個(gè)字符位置。

如果希望使用范圍而不是字符本身來表示待匹配的字符,則可以使用連字符將該范圍的開始和結(jié)束字符分開。每個(gè)字符的字符值將決定其在一個(gè)范圍內(nèi)的相對(duì)順序。下面的 JScript 正則表達(dá)式包含了一個(gè)等價(jià)于上面所示的括號(hào)列表的范圍表達(dá)式。

/Chapter [1-5]/

VBScipt 中相同功能的表達(dá)式如下所示:

"Chapter [1-5]"

如果以這種方式指定范圍,則開始和結(jié)束值都包括在該范圍內(nèi)。有一點(diǎn)特別需要注意的是,在 Unicode 排序中起始值一定要在結(jié)束值之前。

如果想在括號(hào)表達(dá)式中包括連字符,則必須使用下述方法之一:

  • 使用反斜杠將其轉(zhuǎn)義:
    [\-]
  • 將連字符放在括號(hào)列表的開始和結(jié)束位置。下面的表達(dá)式能匹配所有的小寫字母和連字符:
    [-a-z]
    [a-z-]
  • 創(chuàng)建一個(gè)范圍,其中開始字符的值小于連字符,而結(jié)束字符的值等于或大于連字符。下面兩個(gè)正則表達(dá)式都滿足這一要求:
    [!--]
    [!-~]

同樣,通過在列表開始處放置一個(gè)插入符(^),就可以查找所有不在列表或范圍中的字符。如果該插入符出現(xiàn)在列表的其他位置,則匹配其本身,沒有任何特殊含義。下面的 JScript 正則表達(dá)式匹配章節(jié)號(hào)大于 5 的章節(jié)標(biāo)題:

/Chapter [^12345]/

對(duì) VBScript 則使用:

"Chapter [^12345]"

在上面所示的示例中,表達(dá)式將匹配第九個(gè)位置處除1, 2, 3, 4, or 5 之外的任何數(shù)字字符。因此, 'Chapter 7' 為一個(gè)匹配,同樣 'Chapter 9' 也是如此。

上面的表達(dá)式可以使用連字符 (-) 表示。對(duì) JScript 為:

/Chapter [^1-5]/

或者,對(duì) VBScript 為:

"Chapter [^1-5]"

括號(hào)表達(dá)式的典型用法是指定對(duì)任何大寫或小寫字母字符或任何數(shù)字的匹配。下面的 JScript 表達(dá)式給出了這一匹配:

/[A-Za-z0-9]/

等價(jià)的 VBScript 表達(dá)式為:

"[A-Za-z0-9]"

限定符

有時(shí)候不知道要匹配多少字符。為了能適應(yīng)這種不確定性,正則表達(dá)式支持限定符的概念。這些限定符可以指定正則表達(dá)式的一個(gè)給定組件必須要出現(xiàn)多少次才能滿足匹配。

下表給出了各種限定符及其含義的說明:

字符 描述
* 匹配前面的子表達(dá)式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。 * 等價(jià)于{0,}。
+ 匹配前面的子表達(dá)式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等價(jià)于 {1,}。
? 匹配前面的子表達(dá)式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等價(jià)于 {0,1}。
{n} n 是一個(gè)非負(fù)整數(shù)。匹配確定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的兩個(gè) o。
{n,} n 是一個(gè)非負(fù)整數(shù)。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等價(jià)于 'o+'。'o{0,}' 則等價(jià)于 'o*'。
{n,m} mn 均為非負(fù)整數(shù),其中n <= m。最少匹配 n 次且最多匹配 m 次。劉, "o{1,3}" 將匹配 "fooooood" 中的前三個(gè) o。'o{0,1}' 等價(jià)于 'o?'。請(qǐng)注意在逗號(hào)和兩個(gè)數(shù)之間不能有空格。

 

對(duì)一個(gè)很大的輸入文檔而言,章節(jié)數(shù)很輕易就超過九章,因此需要有一種方法來處理兩位數(shù)或者三位數(shù)的章節(jié)號(hào)。限定符就提供了這個(gè)功能。下面的JScript 正則表達(dá)式可以匹配具有任何位數(shù)的章節(jié)標(biāo)題:

/Chapter [1-9][0-9]*/

下面的 VBScript 正則表達(dá)式執(zhí)行同樣的匹配:

"Chapter [1-9][0-9]*"

請(qǐng)注意限定符出現(xiàn)在范圍表達(dá)式之后。因此,它將應(yīng)用于所包含的整個(gè)范圍表達(dá)式,在本例中,只指定了從 0 到 9 的數(shù)字。

這里沒有使用 '+' 限定符,因?yàn)榈诙换蚝罄m(xù)位置上并不一定需要一個(gè)數(shù)字。同樣也沒有使用 '?' 字符,因?yàn)檫@將把章節(jié)數(shù)限制為只有兩位數(shù)字。在 'Chapter' 和空格字符之后至少要匹配一個(gè)數(shù)字。

如果已知章節(jié)數(shù)限制只有99 章,則可以使用下面的 JScript 表達(dá)式來指定至少有一位數(shù)字,但不超過兩個(gè)數(shù)字。

/Chapter [0-9]{1,2}/

對(duì) VBScript 可以使用下述正則表達(dá)式:

"Chapter [0-9]{1,2}"

上述表達(dá)式的缺點(diǎn)是如果有一個(gè)章節(jié)號(hào)大于 99,它仍只會(huì)匹配前兩位數(shù)字。另一個(gè)缺點(diǎn)是某些人可以創(chuàng)建一個(gè) Chapter 0,而且仍能匹配。一個(gè)更好的用來匹配兩位數(shù)的 JScript 表達(dá)式如下:

/Chapter [1-9][0-9]?/

或者

/Chapter [1-9][0-9]{0,1}/

對(duì) VBScript 而言,下述表達(dá)式與上面等價(jià):

"Chapter [1-9][0-9]?"

或者

"Chapter [1-9][0-9]{0,1}"

'*'、 '+'和 '?' 限定符都稱之為貪婪的,也就是說,他們盡可能多地匹配文字。有時(shí)這根本就不是所希望發(fā)生的情況。有時(shí)則正好希望最小匹配。

例如,你可能要搜索一個(gè) HTML 文檔來查找一處包含在 H1 標(biāo)記中的章節(jié)標(biāo)題。在文檔中該文字可能具有如下形式:

<H1>Chapter 1 – Introduction to Regular Expressions</H1>

下面的表達(dá)式匹配從開始的小于號(hào) (<) 到 H1 標(biāo)記結(jié)束處的大于號(hào)之間的所有內(nèi)容。

/<.*>/

 VBScript 的正則表達(dá)式為:

"<.*>"

如果所要匹配的就是開始的 H1 標(biāo)記,則下述非貪婪地表達(dá)式就只匹配 <H1>。

/<.*?>/

或者

"<.*?>"

通過在 '*'、 '+' 或 '?' 限定符后放置 '?',該表達(dá)式就從貪婪匹配轉(zhuǎn)為了非貪婪或最小匹配。

定位符

到現(xiàn)在為止,所看到的示例都只考慮查找任何地方出現(xiàn)的章節(jié)標(biāo)題。出現(xiàn)的任何一個(gè)字符串 'Chapter' 后跟一個(gè)空格和一個(gè)數(shù)字可能是一個(gè)真正的章節(jié)標(biāo)題,也可能是對(duì)其他章節(jié)的交叉引用。由于真正的章節(jié)標(biāo)題總是出現(xiàn)在一行的開始,因此需要設(shè)計(jì)一個(gè)方法只查找標(biāo)題而不查找交叉引用。

定位符提供了這個(gè)功能。定位符可以將一個(gè)正則表達(dá)式固定在一行的開始或結(jié)束。也可以創(chuàng)建只在單詞內(nèi)或只在單詞的開始或結(jié)尾處出現(xiàn)的正則表達(dá)式。下表包含了正則表達(dá)式及其含義的列表:

字符 描述
^ 匹配輸入字符串的開始位置。如果設(shè)置了 RegExp 對(duì)象的 Multiline 屬性,^ 也匹配 '\n' 或 '\r' 之后的位置。
$ 匹配輸入字符串的結(jié)束位置。如果設(shè)置了RegExp 對(duì)象的 Multiline 屬性,$ 也匹配 '\n' 或 '\r' 之前的位置。
\b 匹配一個(gè)單詞邊界,也就是指單詞和空格間的位置。
\B 匹配非單詞邊界。

 

不能對(duì)定位符使用限定符。因?yàn)樵谝粋€(gè)換行符或者單詞邊界的前面或后面不會(huì)有連續(xù)多個(gè)位置,因此諸如 '^*' 的表達(dá)式是不允許的。

要匹配一行文字開始位置的文字,請(qǐng)?jiān)谡齽t表達(dá)式的開始處使用 '^' 字符。不要把 '^' 的這個(gè)語法與其在括號(hào)表達(dá)式中的語法弄混。它們的語法根本不同。

要匹配一行文字結(jié)束位置的文字,請(qǐng)?jiān)谡齽t表達(dá)式的結(jié)束處使用 '$' 字符。

要在查找章節(jié)標(biāo)題時(shí)使用定位符,下面的 JScript 正則表達(dá)式將匹配位于一行的開始處最多有兩個(gè)數(shù)字的章節(jié)標(biāo)題:

/^Chapter [1-9][0-9]{0,1}/

VBScript 中相同功能的正則表達(dá)式如下:

"^Chapter [1-9][0-9]{0,1}"

一個(gè)真正的章節(jié)標(biāo)題不僅出現(xiàn)在一行的開始,而且這一行中也僅有這一個(gè)內(nèi)容,因此,它必然也位于一行的結(jié)束。下面的表達(dá)式確保所指定的匹配只匹配章節(jié)而不會(huì)匹配交叉引用。它是通過創(chuàng)建一個(gè)只匹配一行文字的開始和結(jié)束位置的正則表達(dá)式來實(shí)現(xiàn)的。

/^Chapter [1-9][0-9]{0,1}$/

對(duì) VBScript 則使用:

"^Chapter [1-9][0-9]{0,1}$"

匹配單詞邊界有少許不同,但卻給正則表達(dá)式增加了一個(gè)非常重要的功能。單詞邊界就是單詞和空格之間的位置。非單詞邊界就是其他任何位置。下面的 JScript 表達(dá)式將匹配單詞 'Chapter' 的前三個(gè)字符,因?yàn)樗鼈兂霈F(xiàn)在單詞邊界后:

/\bCha/

對(duì) VBScript 為:

"\bCha"

這里 '\b' 操作符的位置很關(guān)鍵。如果它位于要匹配的字符串的開始,則將查找位于單詞開頭處的匹配;如果它位于改字符串的末尾,則查找位于單詞結(jié)束處的匹配。例如,下面的表達(dá)式將匹配單詞 'Chapter' 中的 'ter',因?yàn)樗霈F(xiàn)在單詞邊界之前:

/ter\b/

以及

"ter\b"

下面的表達(dá)式將匹配 'apt',因?yàn)樗挥?'Chapter' 中間,但不會(huì)匹配 'aptitude' 中的'apt':

/\Bapt/

以及

"\Bapt"

這是因?yàn)樵趩卧~ 'Chapter' 中 'apt' 出現(xiàn)在非單詞邊界位置,而在單詞 'aptitude' 中位于單詞邊界位置。非單詞邊界操作符的位置不重要,因?yàn)槠ヅ渑c一個(gè)單詞的開頭或結(jié)尾無關(guān)。

選擇與編組

選擇允許使用 '|' 字符來在兩個(gè)或多個(gè)候選項(xiàng)中進(jìn)行選擇。通過擴(kuò)展章節(jié)標(biāo)題的正則表達(dá)式,可以將其擴(kuò)充為不僅僅適用于章節(jié)標(biāo)題的表達(dá)式。不過,這可沒有想象的那么直接。在使用選擇時(shí),將匹配'|' 字符每邊最可能的表達(dá)式。你可能認(rèn)為下面的 JScript 和 VBScript 表達(dá)式將匹配位于一行的開始和結(jié)束位置且后跟一個(gè)或兩個(gè)數(shù)字的 'Chapter' 或 'Section':

/^Chapter|Section [1-9][0-9]{0,1}$/
"^Chapter|Section [1-9][0-9]{0,1}$"

不幸的是,真正的情況是上面所示的正則表達(dá)式要么匹配位于一行開始處的單詞 'Chapter',要么匹配一行結(jié)束處的后跟任何數(shù)字的 'Section'。如果輸入字符串為 'Chapter 22',上面的表達(dá)式將只匹配單詞 'Chapter'。如果輸入字符串為 'Section 22',則該表達(dá)式將匹配 'Section 22'。但這種結(jié)果不是我們此處的目的,因此必須有一種辦法來使正則表達(dá)式對(duì)于所要做的更易于響應(yīng),而且確實(shí)也有這種方法。

可以使用圓括號(hào)來限制選擇的范圍,也就是說明確該選擇只適用于這兩個(gè)單詞 'Chapter' 和 'Section'。不過,圓括號(hào)同樣也是難處理的,因?yàn)樗鼈円灿脕韯?chuàng)建子表達(dá)式,有些內(nèi)容將在后面關(guān)于子表達(dá)式的部分介紹。通過采用上面所示的正則表達(dá)式并在適當(dāng)位置添加圓括號(hào),就可以使該正則表達(dá)式既可以匹配 'Chapter 1',也可以匹配 'Section 3'。

下面的正則表達(dá)式使用圓括號(hào)將 'Chapter' 和 'Section' 組成一組,所以該表達(dá)式才能正確工作。對(duì) JScript 為:

/^(Chapter|Section) [1-9][0-9]{0,1}$/

對(duì) VBScript 為:

"^(Chapter|Section) [1-9][0-9]{0,1}$"

這些表達(dá)式工作正確,只是產(chǎn)生了一個(gè)有趣的副產(chǎn)品。在 'Chapter|Section' 兩邊放置圓括號(hào)建立了適當(dāng)?shù)木幗M,但也導(dǎo)致兩個(gè)待匹配單詞之一都被捕獲供今后使用。由于在上面所示的表達(dá)式中只有一組圓括號(hào),因此只能有一個(gè)捕獲的 submatch??梢允褂?VBScript 的Submatches 集合或者JScript 中RegExp 對(duì)象的 $1-$9 屬性來引用這個(gè)子匹配。

有時(shí)捕獲一個(gè)子匹配是所希望的,有時(shí)則是不希望的。在說明所示的示例中,真正想做的就是使用圓括號(hào)對(duì)單詞 'Chapter' 或 'Section' 之間的選擇編組。并不希望在后面再引用該匹配。實(shí)際上,除非真的是需要捕獲子匹配,否則請(qǐng)不要使用。由于不需要花時(shí)間和內(nèi)存來存儲(chǔ)那些子匹配,這種正則表達(dá)式的效率將更高。

可以在正則表達(dá)式模式圓括號(hào)內(nèi)部的前面使用 '?:'來防止存儲(chǔ)該匹配供今后使用。對(duì)上面所示正則表達(dá)式的下述修改提供了免除子匹配存儲(chǔ)的相同功能。對(duì) JScript:

/^(?:Chapter|Section) [1-9][0-9]{0,1}$/

對(duì) VBScript:

"^(?:Chapter|Section) [1-9][0-9]{0,1}$"

除了 '?:' 元字符,還有兩個(gè)非捕獲元字符用于稱之為預(yù)查的匹配。一個(gè)為正向預(yù)查,用 ?= 表示, 在任何開始匹配圓括號(hào)內(nèi)的正則表達(dá)式模式的位置來匹配搜索字符串。一個(gè)為負(fù)向預(yù)查,用 '?!' 表示,在任何開始不匹配該正則表達(dá)式模式的位置來匹配搜索字符串。

例如,假定有一個(gè)包含引用有 Windows 3.1、Windows 95、Windows 98 以及 Windows NT 的文檔。進(jìn)一步假設(shè)需要更新該文檔,方法是查找所有對(duì) Windows 95、Windows 98 以及 Windows NT 的引用,并將這些引用更改為 Windows 2000??梢允褂孟旅娴?JScript 正則表達(dá)式,這是一個(gè)正向預(yù)查,來匹配 Windows 95、Windows 98 以及 Windows NT:

/Windows(?=95 |98 |NT )/

在 VBScript 要進(jìn)行同樣的匹配可以使用下述表達(dá)式:

"Windows(?=95 |98 |NT )"

找到一個(gè)匹配后,緊接匹配到的文字(而不包括預(yù)查中使用的字符)就開始對(duì)下一次匹配的搜索。例如,如果上面所示的表達(dá)式匹配到 'Windows 98',則將從 'Windows' 而不是 '98' 之后繼續(xù)查找。

后向引用

正則表達(dá)式一個(gè)最重要的特性就是將匹配成功的模式的某部分進(jìn)行存儲(chǔ)供以后使用這一能力。請(qǐng)回想一下,對(duì)一個(gè)正則表達(dá)式模式或部分模式兩邊添加圓括號(hào)將導(dǎo)致這部分表達(dá)式存儲(chǔ)到一個(gè)臨時(shí)緩沖區(qū)中??梢允褂梅遣东@元字符 '?:', '?=', or '?!' 來忽略對(duì)這部分正則表達(dá)式的保存。

所捕獲的每個(gè)子匹配都按照在正則表達(dá)式模式中從左至右所遇到的內(nèi)容存儲(chǔ)。存儲(chǔ)子匹配的緩沖區(qū)編號(hào)從 1 開始,連續(xù)編號(hào)直至最大 99 個(gè)子表達(dá)式。每個(gè)緩沖區(qū)都可以使用 '\n' 訪問,其中 n 為一個(gè)標(biāo)識(shí)特定緩沖區(qū)的一位或兩位十進(jìn)制數(shù)。

后向引用一個(gè)最簡(jiǎn)單,最有用的應(yīng)用是提供了確定文字中連續(xù)出現(xiàn)兩個(gè)相同單詞的位置的能力。請(qǐng)看下面的句子:

Is is the cost of of gasoline going up up?

根據(jù)所寫內(nèi)容,上面的句子明顯存在單詞多次重復(fù)的問題。如果能有一種方法無需查找每個(gè)單詞的重復(fù)現(xiàn)象就能修改該句子就好了。下面的 JScript 正則表達(dá)式使用一個(gè)子表達(dá)式就可以實(shí)現(xiàn)這一功能。

/\b([a-z]+) \1\b/gi

等價(jià)的 VBScript 表達(dá)式為:

"\b([a-z]+) \1\b"

在這個(gè)示例中,子表達(dá)式就是圓括號(hào)之間的每一項(xiàng)。所捕獲的表達(dá)式包括一個(gè)或多個(gè)字母字符,即由'[a-z]+' 所指定的。該正則表達(dá)式的第二部分是對(duì)前面所捕獲的子匹配的引用,也就是由附加表達(dá)式所匹配的第二次出現(xiàn)的單詞。'\1'用來指定第一個(gè)子匹配。單詞邊界元字符確保只檢測(cè)單獨(dú)的單詞。如果不這樣,則諸如 "is issued" 或 "this is" 這樣的短語都會(huì)被該表達(dá)式不正確地識(shí)別。

在 JScript 表達(dá)式中,正則表達(dá)式后面的全局標(biāo)志 ('g') 表示該表達(dá)式將用來在輸入字符串中查找盡可能多的匹配。大小寫敏感性由表達(dá)式結(jié)束處的大小寫敏感性標(biāo)記 ('i') 指定。多行標(biāo)記指定可能出現(xiàn)在換行符的兩端的潛在匹配。對(duì) VBScript 而言,在表達(dá)式中不能設(shè)置各種標(biāo)記,但必須使用 RegExp 對(duì)象的屬性來顯式設(shè)置。

使用上面所示的正則表達(dá)式,下面的 JScript 代碼可以使用子匹配信息,在一個(gè)文字字符串中將連續(xù)出現(xiàn)兩次的相同單詞替換為一個(gè)相同的單詞:

var ss = "Is is the cost of of gasoline going up up?.\n";
var re = /\b([a-z]+) \1\b/gim;       //創(chuàng)建正則表達(dá)式樣式.
var rv = ss.replace(re,"$1");   //用一個(gè)單詞替代兩個(gè)單詞.

最接近的等價(jià)  VBScript 代碼如下:

Dim ss, re, rv
ss = "Is is the cost of of gasoline going up up?." & vbNewLine
Set re = New RegExp
re.Pattern = "\b([a-z]+) \1\b"
re.Global = True
re.IgnoreCase = True
re.MultiLine = True
rv = re.Replace(ss,"$1")

請(qǐng)注意在 VBScript 代碼中,全局、大小寫敏感性以及多行標(biāo)記都是使用 RegExp 對(duì)象的適當(dāng)屬性來設(shè)置的。

replace 方法中使用 $1 來引用所保存的第一個(gè)子匹配。如果有多個(gè)子匹配,則可以用 $2, $3 等繼續(xù)引用。

后向引用的另一個(gè)用途是將一個(gè)通用資源指示符 (URI) 分解為組件部分。假定希望將下述的URI 分解為協(xié)議 (ftp, http, etc),域名地址以及頁面/路徑:

http://msdn.microsoft.com:80/scripting/default.htm

下面的正則表達(dá)式可以提供這個(gè)功能。對(duì) JScript,為:

/(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)/

對(duì) VBScript 為:

"(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)"

第一個(gè)附加子表達(dá)式是用來捕獲該 web 地址的協(xié)議部分。該子表達(dá)式匹配位于一個(gè)冒號(hào)和兩個(gè)正斜杠之前的任何單詞。第二個(gè)附加子表達(dá)式捕獲該地址的域名地址。該子表達(dá)式匹配不包括 '^'、 '/' 或 ':' 字符的任何字符序列。第三個(gè)附加子表達(dá)式捕獲網(wǎng)站端口號(hào)碼,如果指定了該端口號(hào)。該子表達(dá)式匹配后跟一個(gè)冒號(hào)的零或多個(gè)數(shù)字。最后,第四個(gè)附加子表達(dá)式捕獲由該 web 地址指定的路徑以及\或者頁面信息。該子表達(dá)式匹配一個(gè)和多個(gè)除'#' 或空格之外的字符。

將該正則表達(dá)式應(yīng)用于上面所示的 URI 后,子匹配包含下述內(nèi)容:

RegExp.$1 包含 "http"

RegExp.$2 包含 "msdn.microsoft.com"

RegExp.$3 包含 ":80"

RegExp.$4 包含 "/scripting/default.htm"



snoics 2005-10-09 15:01 發(fā)表評(píng)論
]]>
常用正則表達(dá)式[轉(zhuǎn)http://www.aygfsteel.com/snoics/articles/15058.htmlsnoicssnoicsSun, 09 Oct 2005 06:57:00 GMThttp://www.aygfsteel.com/snoics/articles/15058.htmlhttp://www.aygfsteel.com/snoics/comments/15058.htmlhttp://www.aygfsteel.com/snoics/articles/15058.html#Feedback0http://www.aygfsteel.com/snoics/comments/commentRss/15058.htmlhttp://www.aygfsteel.com/snoics/services/trackbacks/15058.html一、驗(yàn)證類
1、數(shù)字驗(yàn)證內(nèi)
1.1 整數(shù)
/^(-│+)?d+$/  不可以為空
/^[-+]?d*$/ 可以為空
1.2 大于0的整數(shù) (用于傳來的ID的驗(yàn)證)
/^d+$/
1.3 負(fù)整數(shù)的驗(yàn)證
/^-d+$/
1.4 整數(shù)不能大于iMax
根據(jù)上面的正則可以寫出。
1.5 整數(shù)不能小于iMin
根據(jù)上面的正則可以寫出。
2、時(shí)間類
2.1 短時(shí)間,形如 (13:04:06)
    function isTime(str)
{
var a = str.match(/^(d)(:)?(d)2(d)$/);
if (a == null) {alert('輸入的參數(shù)不是時(shí)間格式'); return false;}
if (a[1]>24 ││ a[3]>60 ││ a[4]>60)
{
alert("時(shí)間格式不對(duì)");
return false
}
return true;
}

2.2 短日期,形如 (2003-12-05)
function strDateTime(str)
{
var r = str.match(/^(d)(-│/)(d)2(d)$/);
if(r==null)return false;
var d= new Date(r[1], r[3]-1, r[4]);
return (d.getFullYear()==r[1]&&(d.getMonth()+1)==r[3]&&d.getDate()==r[4]);
}

2.3 長(zhǎng)時(shí)間,形如 (2003-12-05 13:04:06)
function strDateTime(str)
{
var reg = /^(d)(-│/)(d)2(d) (d):(d):(d)$/;
var r = str.match(reg);
if(r==null)return false;
var d= new Date(r[1], r[3]-1,r[4],r[5],r[6],r[7]);
return (d.getFullYear()==r[1]&&(d.getMonth()+1)==r[3]&&d.getDate()==r[4]&&d.getHours()==r[5]&&d.getMinutes()==r[6]&&d.getSeconds()==r[7]);
}

2.4 只有年和月。形如(2003-05,或者2003-5)

2.5 只有小時(shí)和分鐘,形如(12:03)
3、表單類
3.1 所有的表單的值都不能為空
<input onblur="if(this.value.replace(/^s+│s+$/g,'')=='')alert('不能為空!')">

3.2 多行文本框的值不能為空。
3.3 多行文本框的值不能超過sMaxStrleng
//檢驗(yàn)文本框中內(nèi)容是否超長(zhǎng)
function CheckTextareaLength(val, max_length) {
var str_area=document.forms[0].elements[val].value;
if (str_area!=null&&str_area.length > max_length)
{
alert("字段文字超長(zhǎng),最多可輸入" + max_length +"個(gè)字符,請(qǐng)重新輸入!");
document.forms[0].elements[val].focus();
document.forms[0].elements[val].select();
return false;
}
return true;
}
3.4 多行文本框的值不能少于sMixStrleng
3.5 判斷單選框是否選擇。

function CheckRadio(val,msg1,msg2)
{
var is_radio=document.forms[0].elements[val];
var s_msg1=(msg1==null ││ msg1=="")? "請(qǐng)選擇 radio!":msg1;
var s_msg2=(msg2==null ││ msg2=="")? "沒有可選的 radio!":msg2;

if(is_radio)
{
if (document.forms[0].elements[val].value != null)
{
if (document.forms[0].elements[val].checked)
{
return true;
}
else
{
alert(s_msg1);
return false;
}
}
else
{
var check_length = document.forms[0].elements[val].length;
var i_count=0
for(var i=0;i<check_length;i++)
{
if (document.forms[0].elements[val](i).checked)
{
i_count=i_count+1;
return true;
}
}
if(i_count==0)
{
alert(s_msg1);
return false;
}
}
}//
else
{
alert(s_msg2);
return false;
}

}
3.6 判斷復(fù)選框是否選擇.
function CheckCheckbox(val,msg1,msg2)
{
var is_radio=document.forms[0].elements[val];
var s_msg1=(msg1==null ││ msg1=="")? "請(qǐng)選擇CheckBox!":msg1;
var s_msg2=(msg2==null ││ msg2=="")? "沒有可選的CheckBox!":msg2;

if(is_radio)
{
if (document.forms[0].elements[val].value != null)
{
if (document.forms[0].elements[val].checked)
{
return true;
}
else
{
alert(s_msg1);
return false;
}
}
else
{
var check_length = document.forms[0].elements[val].length;
var i_count=0
for(var i=0;i<check_length;i++)
{
if (document.forms[0].elements[val](i).checked)
{
i_count=i_count+1;
return true;
}
}
if(i_count==0)
{
alert(s_msg1);
return false;
}
}
}//
else
{
alert(s_msg2);
return false;
}

}
3.7 復(fù)選框的全選,多選,全不選,反選
<form name=hrong>
<input type=checkbox name=All onclick="checkAll('mm')">全選<br/>
<input type=checkbox name=mm onclick="checkItem('All')"><br/>
<input type=checkbox name=mm onclick="checkItem('All')"><br/>
<input type=checkbox name=mm onclick="checkItem('All')"><br/>
<input type=checkbox name=mm onclick="checkItem('All')"><br/>
<input type=checkbox name=mm onclick="checkItem('All')"><br/><br/>


<input type=checkbox name=All2 onclick="checkAll('mm2')">全選<br/>
<input type=checkbox name=mm2 onclick="checkItem('All2')"><br/>
<input type=checkbox name=mm2 onclick="checkItem('All2')"><br/>
<input type=checkbox name=mm2 onclick="checkItem('All2')"><br/>
<input type=checkbox name=mm2 onclick="checkItem('All2')"><br/>
<input type=checkbox name=mm2 onclick="checkItem('All2')"><br/>

</form>

<SCRIPT LANGUAGE="JavaScript">
function checkAll(str)
{
var a = document.getElementsByName(str);
var n = a.length;
for (var i=0; i<n; i++)
a[i].checked = window.event.srcElement.checked;
}
function checkItem(str)
{
var e = window.event.srcElement;
var all = eval("document.hrong."+ str);
if (e.checked)
{
var a = document.getElementsByName(e.name);
all.checked = true;
for (var i=0; i<a.length; i++)
{
if (!a[i].checked){ all.checked = false; break;}
}
}
else all.checked = false;
}
</SCRIPT>


3.8 文件上傳過程中判斷文件類型
<input type=file onchange="alert(this.value.match(/^(.*)(.)(.)$/)[3])">

4、字符類
4.1 判斷字符全部由a-Z或者是A-Z的字字母組成
<input onblur="if(/[^a-zA-Z]/g.test(this.value))alert('有錯(cuò)')">
4.2 判斷字符由字母和數(shù)字組成。
<input onblur="if(/[^0-9a-zA-Z]/g.test(this.value))alert('有錯(cuò)')">

4.3 判斷字符由字母和數(shù)字,下劃線,點(diǎn)號(hào)組成.且開頭的只能是下劃線和字母
/^([a-zA-z_])([w]*)$/g.test(str)

4.4 字符串替換函數(shù).Replace();
5、瀏覽器類
5.1 判斷瀏覽器的類型
window.navigator.appName
5.2 判斷ie的版本
window.navigator.appVersion
5.3 判斷客戶端的分辨率
window.screen.height; window.screen.width;

6、結(jié)合類
6.1 email的判斷。
function ismail(mail)
{
return(new RegExp(/^w+((-w+)│(.w+))*@[A-Za-z0-9]+((.│-)[A-Za-z0-9]+)*.[A-Za-z0-9]+$/).test(mail));
}

6.2 手機(jī)號(hào)碼的驗(yàn)證
6.3 身份證的驗(yàn)證
function isIdCardNo(num)
{
if (isNaN(num)) {alert("輸入的不是數(shù)字!"); return false;}
var len = num.length, re;
if (len == 15)
re = new RegExp(/^(d)()?(d)(d)(d)(d)$/);
else if (len == 18)
re = new RegExp(/^(d)()?(d)(d)(d)(d)(d)$/);
else {alert("輸入的數(shù)字位數(shù)不對(duì)!"); return false;}
var a = num.match(re);
if (a != null)
{
if (len==15)
{
var D = new Date("19"+a[3]+"/"+a[4]+"/"+a[5]);
var B = D.getYear()==a[3]&&(D.getMonth()+1)==a[4]&&D.getDate()==a[5];
}
else
{
var D = new Date(a[3]+"/"+a[4]+"/"+a[5]);
var B = D.getFullYear()==a[3]&&(D.getMonth()+1)==a[4]&&D.getDate()==a[5];
}
if (!B) {alert("輸入的身份證號(hào) "+ a[0] +" 里出生日期不對(duì)!"); return false;}
}
return true;
}
   另外一個(gè)
<script>
var aCity=

function cidInfo(sId){
var iSum=0
var info=""
if(!/^d(d│x)$/i.test(sId))return false;
sId=sId.replace(/x$/i,"a");
if(aCity[parseInt(sId.substr(0,2))]==null)return "Error:非法地區(qū)";
sBirthday=sId.substr(6,4)+"-"+Number(sId.substr(10,2))+"-"+Number(sId.substr(12,2));
var d=new Date(sBirthday.replace(/-/g,"/"))
if(sBirthday!=(d.getFullYear()+"-"+ (d.getMonth()+1) + "-" + d.getDate()))return "Error:非法生日";
for(var i = 17;i>=0;i --) iSum += (Math.pow(2,i) % 11) * parseInt(sId.charAt(17 - i),11)
if(iSum%11!=1)return "Error:非法證號(hào)";
return aCity[parseInt(sId.substr(0,2))]+","+sBirthday+","+(sId.substr(16,1)%2?"男":"女")
}

document.write(cidInfo("380524198002300016"),"<br/>");
document.write(cidInfo("340524198002300019"),"<br/>")
document.write(cidInfo("340524197711111111"),"<br/>")
document.write(cidInfo("34052419800101001x"),"<br/>");
</script>
6.4?。椋鸬刂沸r?yàn)
<SCRIPT LANGUAGE="JavaScript">
function isip(s){
var check=function(v){try{return (v<=255 && v>=0)}catch(x){return false}};
var re=s.split(".")
return (re.length==4)?(check(re[0]) && check(re[1]) && check(re[2]) && check(re[3])):false
}

var s="202.197.78.129";
alert(isip(s))
</SCRIPT>
6.5 .加sp1后還能用的無邊框窗口?。?BR><HTML XMLNS:IE>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<IE:Download ID="include" STYLE="behavior:url(#default#download)" />
<title>Chromeless Window</title>

<SCRIPT LANGUAGE="JScript">
/*--- Special Thanks For andot ---*/

/*
This following code are designed and writen by Windy_sk <seasonx@163.net>
You can use it freely, but u must held all the copyright items!
*/

/*--- Thanks For andot Again ---*/

var CW_width = 400;
var CW_height = 300;
var CW_top = 100;
var CW_left = 100;
var CW_url = "/";
var New_CW = window.createPopup();
var CW_Body = New_CW.document.body;
var content = "";
var CSStext = "margin:1px;color:black; border:2px outset;border-style:expression(onmouseout=onmouseup=function(), onmousedown=function());background-color:buttonface;width:16px;height:14px;font-size:12px;line-height:11px;cursor:Default;";

//Build Window
include.startDownload(CW_url, function(source));

function insert_content(){
var temp = "";
CW_Body.style.overflow = "hidden";
CW_Body.style.backgroundColor = "white";
CW_Body.style.border = "solid black 1px";
content = content.replace(/<a ([^>]*)>/g,"<a onclick='parent.open(this.href);return false' >");
temp += "<table width=100% height=100% cellpadding=0 cellspacing=0 border=0>";
temp += "<tr style=';font-size:12px;background:#0099CC;height:20;cursor:default' ondblclick="Max.innerText=Max.innerText=='1'?'2':'1';parent.if_max=!parent.if_max;parent.show_CW();" onmouseup='parent.drag_up(event)' onmousemove='parent.drag_move(event)' onmousedown='parent.drag_down(event)' onselectstart='return false' oncontextmenu='return false'>";
temp += "<td style='color:#ffffff;padding-left:5px'>Chromeless Window For IE6 SP1</td>";
temp += "<td style='color:#ffffff;padding-right:5px;' align=right>";
temp += "<span id=Help onclick="alert('Chromeless Window For IE6 SP1 - Ver 1.0\n\nCode By Windy_sk\n\nSpecial Thanks For andot')" style=""+CSStext+"font-family:System;padding-right:2px;">?</span>";
temp += "<span id=Min onclick='parent.New_CW.hide();parent.blur()' style=""+CSStext+"font-family:Webdings;" title='Minimum'>0</span>";
temp += "<span id=Max onclick="this.innerText=this.innerText=='1'?'2':'1';parent.if_max=!parent.if_max;parent.show_CW();" style=""+CSStext+"font-family:Webdings;" title='Maximum'>1</span>";
temp += "<span id=Close onclick='parent.opener=null;parent.close()' style=""+CSStext+"font-family:System;padding-right:2px;" title='Close'>x</span>";
temp += "</td></tr><tr><td colspan=2>";
temp += "<div id=include style='overflow:scroll;overflow-x:hidden;overflow-y:auto; HEIGHT: 100%; width:"+CW_width+"'>";
temp += content;
temp += "</div>";
temp += "</td></tr></table>";
CW_Body.innerHTML = temp;
}

setTimeout("insert_content()",1000);

var if_max = true;
function show_CW(){
window.moveTo(10000, 10000);
if(if_max){
New_CW.show(CW_top, CW_left, CW_width, CW_height);
if(typeof(New_CW.document.all.include)!="undefined"){
New_CW.document.all.include.style.width = CW_width;
New_CW.document.all.Max.innerText = "1";
}

}else{
New_CW.show(0, 0, screen.width, screen.height);
New_CW.document.all.include.style.width = screen.width;
}
}

window.onfocus = show_CW;
window.onresize = show_CW;

// Move Window
var drag_x,drag_y,draging=false

function drag_move(e){
if (draging){
New_CW.show(e.screenX-drag_x, e.screenY-drag_y, CW_width, CW_height);
return false;
}
}

function drag_down(e){
if(e.button==2)return;
if(New_CW.document.body.offsetWidth==screen.width && New_CW.document.body.offsetHeight==screen.height)return;
drag_x=e.clientX;
drag_y=e.clientY;
draging=true;
e.srcElement.setCapture();
}

function drag_up(e){
draging=false;
e.srcElement.releaseCapture();
if(New_CW.document.body.offsetWidth==screen.width && New_CW.document.body.offsetHeight==screen.height) return;
CW_top = e.screenX-drag_x;
CW_left = e.screenY-drag_y;
}

</SCRIPT>
</HTML>

6.6 電話號(hào)碼的驗(yàn)證

要求:
  (1)電話號(hào)碼由數(shù)字、"("、")"和"-"構(gòu)成
  (2)電話號(hào)碼為3到8位
  (3)如果電話號(hào)碼中包含有區(qū)號(hào),那么區(qū)號(hào)為三位或四位
  (4)區(qū)號(hào)用"("、")"或"-"和其他部分隔開
  (5)移動(dòng)電話號(hào)碼為11或12位,如果為12位,那么第一位為0
  (6)11位移動(dòng)電話號(hào)碼的第一位和第二位為"13"
  (7)12位移動(dòng)電話號(hào)碼的第二位和第三位為"13"
  根據(jù)這幾條規(guī)則,可以與出以下正則表達(dá)式:
  (^[0-9]-[0-9]$)│(^[0-9]$)│(^([0-9])[0-9]$)│(^013[0-9]$)


<script language="javascript">
function PhoneCheck(s) {
var str=s;
var reg=/(^[0-9]-[0-9]$)│(^[0-9]$)│(^([0-9])[0-9]$)│(^013[0-9]$)/
alert(reg.test(str));
}
</script>
<input type=text name="iphone">
<input type=button onclick="PhoneCheck(document.all.iphone.value)" value="Check">

二、功能類

1、時(shí)間與相關(guān)控件類
1.1 日歷
精華區(qū)的日歷

1.2 時(shí)間控件

1.3 萬年歷
http://202.112.86.128/studentspace/...calendars/rili/
1.4 顯示動(dòng)態(tài)顯示時(shí)鐘效果(文本,如OA中時(shí)間)
特效很容易找到的
1.5 顯示動(dòng)態(tài)顯示時(shí)鐘效果 (圖像,像手表)
特效很容易找到的
2、表單類
2.1 自動(dòng)生成表單
2.2 動(dòng)態(tài)添加,修改,刪除下拉框中的元素
大版主的js寶庫里面的對(duì)select 的操作已經(jīng)可以是精品了。
2.3 可以輸入內(nèi)容的下拉框

2.4 多行文本框中只能輸入iMax文字。如果多輸入了,自動(dòng)減少到iMax個(gè)文字(多用于短信發(fā)送)

3、打印類
3.1 打印控件
<HTML>
<HEAD>
<TITLE> New Document </TITLE>
<META NAME="Generator" CONTENT="EditPlus">
<META NAME="Author" CONTENT="">
<META NAME="Keywords" CONTENT="">
<META NAME="Description" CONTENT="">
<SCRIPT LANGUAGE=javascript>
<!--
function setPrint()

function previewPrint()


//-->
</SCRIPT>
<script language=vbscript>
function setup_page
Dim wsh
Set wsh = CreateObject("WScript.Shell")
on error resume next

wsh.RegWrite "HKCUSoftwareMicrosoftInternet explorerPageSetupheader", "", "REG_SZ"
wsh.RegWrite "HKCUSoftwareMicrosoftInternet ExplorerPageSetupfooter", "", "REG_SZ"

end function

</script>
</HEAD>

<BODY>
<OBJECT classid=CLSID:8856F961-340A-11D0-A96B-00C04FD705A2 height=0 id=WB width=0>
</OBJECT>
<INPUT type="button" value="Set" id=button1 name=button1 onclick="setPrint();">
<INPUT type="button" value="Preview" id=button2 name=button2 onclick="previewPrint();">
<INPUT type="button" value="setup" id=button2 name=button2 onclick="setup_page();">
</BODY>
</HTML>

4、事件類
4.1 屏蔽右鍵
4.2 屏蔽所有功能鍵
4.3 --> 和<-- F5 F11,F9,F1
4.4 屏蔽組合鍵ctrl+N
<script>
//禁止ctrl+n和 禁止ctrl+r和 禁止shift+f10 禁止鼠標(biāo)右鍵or左右鍵 和禁止f5
var oLastBtn=0,bIsMenu=false
if (window.Event)
{
document.captureEvents(Event.MOUSEUP);
}

function nocontextmenu()
{
event.cancelBubble=true;
event.returnValue=false;
return false;
}

function norightclick(e)

{
if(window.Event)
{
if (e.which !=1)
{
return false;
}
}
else
if(event.button!=1)
{
event.cancelBubble=true;
event.returnValue=false;
return false;
}
}

document.oncontextmenu=nocontextmenu;
document.onmousedown=norightclick;

function onKeyDown()
{
if ((event.altKey)││((event.keyCode==8)&&(event.srcElement.type!="text"&&event.srcElement.type!="textarea"&&event.srcElement.type!="password"))││((event.ctrlKey)&&((event.keyCode==78)││(event.keyCode==82)))││(event.keyCode==116))

}
</script>
<body onkeydown="onKeyDown()">
<body>
</html>
5、網(wǎng)頁設(shè)計(jì)類
5.1 連續(xù)滾動(dòng)的文字,圖片(注意是連續(xù)的,兩段文字和圖片中沒有空白出現(xiàn))
5.2 html編輯控件類
5.3 顏色選取框控件
5.4 下拉菜單
5.5 兩層或多層次的下拉菜單
5.6 仿IE菜單的按鈕。(效果如rongshuxa.com的導(dǎo)航欄目)
5.7 狀態(tài)欄,title欄的動(dòng)態(tài)效果(例子很多,可以研究一下)
5.8 雙擊后,網(wǎng)頁自動(dòng)滾屏
以上都是特效類,很容易找到的。
6、樹型結(jié)構(gòu)。
6.1 asp+SQL版
6.2 asp+xml+sql版
6.3 java+sql或者java+sql+xml
7、無邊框效果的制作
8、連動(dòng)下拉框技術(shù)
9、文本排序
10,畫圖類,含餅、柱、矢量貝滋曲線
<OBJECT
id=S
style="LEFT: 0px; WIDTH: 392px; TOP: 0px; HEIGHT: 240px"
height=240
width=392
classid="clsid:369303C2-D7AC-11D0-89D5-00A0C90833E6">
</OBJECT>
<SCRIPT>
S.DrawingSurface.ArcDegrees(0,0,0,30,50,60);
S.DrawingSurface.ArcRadians(30,0,0,30,50,60);
S.DrawingSurface.Line(10,10,100,100);
</SCRIPT>


11,操縱客戶端注冊(cè)表類
<SCRIPT>
var WshShell = WScript.CreateObject("WScript.Shell");
WshShell.RegWrite ("HKCU\Software\ACME\FortuneTeller\", 1, "REG_BINARY");
WshShell.RegWrite ("HKCU\Software\ACME\FortuneTeller\MindReader", "Goocher!", "REG_SZ");
var bKey = WshShell.RegRead ("HKCU\Software\ACME\FortuneTeller\");
WScript.Echo (WshShell.RegRead ("HKCU\Software\ACME\FortuneTeller\MindReader"));
WshShell.RegDelete ("HKCU\Software\ACME\FortuneTeller\MindReader");
WshShell.RegDelete ("HKCU\Software\ACME\FortuneTeller\");
WshShell.RegDelete ("HKCU\Software\ACME\");
</SCRIPT>

12,DIV層相關(guān)(拖拽、顯示、隱藏、移動(dòng)、增加)
13,TABLAE相關(guān)(客戶端動(dòng)態(tài)增加行列,模擬進(jìn)度條,滾動(dòng)列表等)
<HTML>
<SCRIPT LANGUAGE="JScript">
function numberCells() {
var count=0;
for (i=0; i < document.all.mytable.rows.length; i++) {
for (j=0; j < document.all.mytable.rows(i).cells.length; j++) {
document.all.mytable.rows(i).cells(j).innerText = count;
count++;
}
}
}
</SCRIPT>
<BODY onload="numberCells()">
<TABLE id=mytable border=1>
<TR><TH> </TH><TH> </TH><TH> </TH><TH> </TH></TR>
<TR><TD> </TD><TD> </TD><TD> </TD><TD> </TD></TR>
<TR><TD> </TD><TD> </TD><TD> </TD><TD> </TD></TR>
</TABLE>
</BODY>
</HTML>
14,各種<object classid=>相關(guān)類,如播放器,flash與腳本互動(dòng)等
16, 刷新/模擬無刷新 異步調(diào)用類(XMLHttp或iframe,frame)



snoics 2005-10-09 14:57 發(fā)表評(píng)論
]]>
JavaScript中的正則表達(dá)式解析 [轉(zhuǎn)]http://www.aygfsteel.com/snoics/articles/15057.htmlsnoicssnoicsSun, 09 Oct 2005 06:55:00 GMThttp://www.aygfsteel.com/snoics/articles/15057.htmlhttp://www.aygfsteel.com/snoics/comments/15057.htmlhttp://www.aygfsteel.com/snoics/articles/15057.html#Feedback0http://www.aygfsteel.com/snoics/comments/commentRss/15057.htmlhttp://www.aygfsteel.com/snoics/services/trackbacks/15057.html 

        正則表達(dá)式(regular expression)對(duì)象包含一個(gè)正則表達(dá)式模式(pattern)。它具有用正則表達(dá)式模式去匹配或代替一個(gè)串(string)中特定字符(或字符集合)的屬性(properties)和方法(methods)。 要為一個(gè)單獨(dú)的正則表達(dá)式添加屬性,可以使用正則表達(dá)式構(gòu)造函數(shù)(constructor function),無論何時(shí)被調(diào)用的預(yù)設(shè)置的正則表達(dá)式擁有靜態(tài)的屬性(the predefined RegExp object has static properties that are set whenever any regular expression is used, 我不知道我翻得對(duì)不對(duì),將原文列出,請(qǐng)自行翻譯)。

  • 創(chuàng)建:
    一個(gè)文本格式或正則表達(dá)式構(gòu)造函數(shù)
    文本格式: /pattern/flags
    正則表達(dá)式構(gòu)造函數(shù): new RegExp("pattern"[,"flags"]);
  • 參數(shù)說明:
    pattern -- 一個(gè)正則表達(dá)式文本
    flags -- 如果存在,將是以下值:
    g: 全局匹配
    i: 忽略大小寫
    gi: 以上組合

[注意] 文本格式的參數(shù)不用引號(hào),而在用構(gòu)造函數(shù)時(shí)的參數(shù)需要引號(hào)。如:/ab+c/i new RegExp("ab+c","i")是實(shí)現(xiàn)一樣的功能。在構(gòu)造函數(shù)中,一些特殊字符需要進(jìn)行轉(zhuǎn)意(在特殊字符前加"\")。如:re = new RegExp("\\w+")

正則表達(dá)式中的特殊字符

字符 含意
\

做為轉(zhuǎn)意,即通常在"\"后面的字符不按原來意義解釋,如/b/匹配字符"b",當(dāng)b前面加了反斜桿后/\b/,轉(zhuǎn)意為匹配一個(gè)單詞的邊界。
-或-
對(duì)正則表達(dá)式功能字符的還原,如"*"匹配它前面元字符0次或多次,/a*/將匹配a,aa,aaa,加了"\"后,/a\*/將只匹配"a*"。

^ 匹配一個(gè)輸入或一行的開頭,/^a/匹配"an A",而不匹配"An a"
$ 匹配一個(gè)輸入或一行的結(jié)尾,/a$/匹配"An a",而不匹配"an A"
* 匹配前面元字符0次或多次,/ba*/將匹配b,ba,baa,baaa
+ 匹配前面元字符1次或多次,/ba*/將匹配ba,baa,baaa
? 匹配前面元字符0次或1次,/ba*/將匹配b,ba
(x) 匹配x保存x在名為$1...$9的變量中
x|y 匹配x或y
{n} 精確匹配n次
{n,} 匹配n次以上
{n,m} 匹配n-m次
[xyz] 字符集(character set),匹配這個(gè)集合中的任一一個(gè)字符(或元字符)
[^xyz] 不匹配這個(gè)集合中的任何一個(gè)字符
[\b] 匹配一個(gè)退格符
\b 匹配一個(gè)單詞的邊界
\B 匹配一個(gè)單詞的非邊界
\cX 這兒,X是一個(gè)控制符,/\cM/匹配Ctrl-M
\d 匹配一個(gè)字?jǐn)?shù)字符,/\d/ = /[0-9]/
\D 匹配一個(gè)非字?jǐn)?shù)字符,/\D/ = /[^0-9]/
\n 匹配一個(gè)換行符
\r 匹配一個(gè)回車符
\s 匹配一個(gè)空白字符,包括\n,\r,\f,\t,\v等
\S 匹配一個(gè)非空白字符,等于/[^\n\f\r\t\v]/
\t 匹配一個(gè)制表符
\v 匹配一個(gè)重直制表符
\w 匹配一個(gè)可以組成單詞的字符(alphanumeric,這是我的意譯,含數(shù)字),包括下劃線,如[\w]匹配"$5.98"中的5,等于[a-zA-Z0-9]
\W 匹配一個(gè)不可以組成單詞的字符,如[\W]匹配"$5.98"中的$,等于[^a-zA-Z0-9]。

說了這么多了,我們來看一些正則表達(dá)式的實(shí)際應(yīng)用的例子:

E-mail地址驗(yàn)證:
 function test_email(strEmail) {
  var myReg = /^[_a-z0-9]+@([_a-z0-9]+\.)+[a-z0-9]{2,3}$/;
  if(myReg.test(strEmail)) return true;
  return false;
 }
HTML代碼的屏蔽
 function mask_HTMLCode(strInput) {
   var myReg = /<(\w+)>/;
   return strInput.replace(myReg, "&lt;$1&gt;");
 }

正則表達(dá)式對(duì)象的屬性及方法
  預(yù)定義的正則表達(dá)式擁有有以下靜態(tài)屬性:input, multiline, lastMatch, lastParen, leftContext, rightContext和$1到$9。其中input和multiline可以預(yù)設(shè)置。其他屬性的值在執(zhí)行過exec或test方法后被根據(jù)不同條件賦以不同的值。許多屬性同時(shí)擁有長(zhǎng)和短(perl風(fēng)格)的兩個(gè)名字,并且,這兩個(gè)名字指向同一個(gè)值。(JavaScript模擬perl的正則表達(dá)式)
正則表達(dá)式對(duì)象的屬性
屬性 含義
$1...$9 如果它(們)存在,是匹配到的子串
$_ 參見input
$* 參見multiline
$& 參見lastMatch
$+ 參見lastParen
$` 參見leftContext
$’          參見rightContext
constructor    創(chuàng)建一個(gè)對(duì)象的一個(gè)特殊的函數(shù)原型
global       是否在整個(gè)串中匹配(bool型)
ignoreCase     匹配時(shí)是否忽略大小寫(bool型)
input        被匹配的串
lastIndex     最后一次匹配的索引
lastParen     最后一個(gè)括號(hào)括起來的子串
leftContext    最近一次匹配以左的子串
multiline     是否進(jìn)行多行匹配(bool型)
prototype     允許附加屬性給對(duì)象
rightContext    最近一次匹配以右的子串
source       正則表達(dá)式模式
lastIndex     最后一次匹配的索引

正則表達(dá)式對(duì)象的方法
方法 含義
compile      正則表達(dá)式比較
exec        執(zhí)行查找
test        進(jìn)行匹配
toSource      返回特定對(duì)象的定義(literal representing),其值可用來創(chuàng)建一個(gè)新的對(duì)象。重載Object.toSource方法得到的。
toString      返回特定對(duì)象的串。重載Object.toString方法得到的。
valueOf      返回特定對(duì)象的原始值。重載Object.valueOf方法得到
例子
<script language = "JavaScript">
var myReg = /(\w+)\s(\w+)/;
var str  = "John Smith";
var newstr = str.replace(myReg, "$2, $1");
document.write(newstr);
</script>
將輸出"Smith, John"


snoics 2005-10-09 14:55 發(fā)表評(píng)論
]]>
正則表達(dá)式在javascript中的幾個(gè)實(shí)例2(轉(zhuǎn))http://www.aygfsteel.com/snoics/articles/15056.htmlsnoicssnoicsSun, 09 Oct 2005 06:53:00 GMThttp://www.aygfsteel.com/snoics/articles/15056.htmlhttp://www.aygfsteel.com/snoics/comments/15056.htmlhttp://www.aygfsteel.com/snoics/articles/15056.html#Feedback0http://www.aygfsteel.com/snoics/comments/commentRss/15056.htmlhttp://www.aygfsteel.com/snoics/services/trackbacks/15056.html 

javascript正則表達(dá)式檢驗(yàn)
/*********************************************************************************
* EO_JSLib.js
* javascript正則表達(dá)式檢驗(yàn)
**********************************************************************************/

//校驗(yàn)是否全由數(shù)字組成
function isDigit(s)
{
var patrn=/^[0-9]{1,20}$/;
if (!patrn.exec(s)) return false
return true
}

//校驗(yàn)登錄名:只能輸入5-20個(gè)以字母開頭、可帶數(shù)字、“_”、“.”的字串
function isRegisterUserName(s)
{
var patrn=/^[a-zA-Z]{1}([a-zA-Z0-9]|[._]){4,19}$/;
if (!patrn.exec(s)) return false
return true
}

//校驗(yàn)用戶姓名:只能輸入1-30個(gè)以字母開頭的字串
function isTrueName(s)
{
var patrn=/^[a-zA-Z]{1,30}$/;
if (!patrn.exec(s)) return false
return true
}

//校驗(yàn)密碼:只能輸入6-20個(gè)字母、數(shù)字、下劃線
function isPasswd(s)
{
var patrn=/^(\w){6,20}$/;
if (!patrn.exec(s)) return false
return true
}

//校驗(yàn)普通電話、傳真號(hào)碼:可以“+”開頭,除數(shù)字外,可含有“-”
function isTel(s)
{
//var patrn=/^[+]{0,1}(\d){1,3}[ ]?([-]?(\d){1,12})+$/;
var patrn=/^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$/;
if (!patrn.exec(s)) return false
return true
}

//校驗(yàn)手機(jī)號(hào)碼:必須以數(shù)字開頭,除數(shù)字外,可含有“-”
function isMobil(s)
{
var patrn=/^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$/;
if (!patrn.exec(s)) return false
return true
}

//校驗(yàn)郵政編碼
function isPostalCode(s)
{
//var patrn=/^[a-zA-Z0-9]{3,12}$/;
var patrn=/^[a-zA-Z0-9 ]{3,12}$/;
if (!patrn.exec(s)) return false
return true
}

//校驗(yàn)搜索關(guān)鍵字
function isSearch(s)
{
var patrn=/^[^`~!@#$%^&*()+=|\\\][\]\{\}:;'\,.<>/?]{1}[^`~!@$%^&()+=|\\\][\]\{\}:;'\,.<>?]{0,19}$/;
if (!patrn.exec(s)) return false
return true
}

function isIP(s) //by zergling
{
var patrn=/^[0-9.]{1,20}$/;
if (!patrn.exec(s)) return false
return true
}



snoics 2005-10-09 14:53 發(fā)表評(píng)論
]]>
JAVA正則表達(dá)式4種常用功能 [轉(zhuǎn)]http://www.aygfsteel.com/snoics/articles/15055.htmlsnoicssnoicsSun, 09 Oct 2005 06:45:00 GMThttp://www.aygfsteel.com/snoics/articles/15055.htmlhttp://www.aygfsteel.com/snoics/comments/15055.htmlhttp://www.aygfsteel.com/snoics/articles/15055.html#Feedback0http://www.aygfsteel.com/snoics/comments/commentRss/15055.htmlhttp://www.aygfsteel.com/snoics/services/trackbacks/15055.html
JAVA正則表達(dá)式4種常用功能 
   
  正則表達(dá)式在字符串處理上有著強(qiáng)大的功能,sun在jdk1.4加入了對(duì)它的支持 
 
  下面簡(jiǎn)單的說下它的4種常用功能:
  
  查詢:
  
以下是代碼片段:
 String str="abc efg ABC"; 
 
String regEx="a|f"; //表示a或f 
 
 Pattern p=Pattern.compile(regEx); 
 
 Matcher m=p.matcher(str); 
 
 boolean rs=m.find(); 

  
  如果str中有regEx,那么rs為true,否則為flase。如果想在查找時(shí)忽略大小寫,則可以寫成Pattern p=Pattern.compile(regEx,Pattern.CASE_INSENSITIVE);
  
  提取:
以下是代碼片段:
 String regEx=".+\(.+)$"; 
 
String str="c:\dir1\dir2\name.txt"; 
 
 Pattern p=Pattern.compile(regEx); 
 
 Matcher m=p.matcher(str); 
 
 boolean rs=m.find(); 
 
 for(int i=1;i<=m.groupCount();i++){ 
 
 System.out.println(m.group(i)); 
 
 } 

  
  以上的執(zhí)行結(jié)果為name.txt,提取的字符串儲(chǔ)存在m.group(i)中,其中i最大值為m.groupCount();
  
  分割:
  
以下是代碼片段:
String regEx="::"; 
 
 Pattern p=Pattern.compile(regEx); 
 
 String[] r=p.split("xd::abc::cde"); 
 
 執(zhí)行后,r就是{"xd","abc","cde"},其實(shí)分割時(shí)還有跟簡(jiǎn)單的方法: 
 
 String str="xd::abc::cde"; 
 
 String[] r=str.split("::"); 

  
  替換(刪除):
  
以下是代碼片段:
 String regEx="a+"; //表示一個(gè)或多個(gè)a 

 Pattern p=Pattern.compile(regEx); 
 
 Matcher m=p.matcher("aaabbced a ccdeaa"); 
 
 String s=m.replaceAll("A"); 
  
  結(jié)果為"Abbced A ccdeA"
  
  如果寫成空串,既可達(dá)到刪除的功能,比如:
  
String s=m.replaceAll("");
  
  結(jié)果為"bbced ccde"
  
  附:
  
 \D 等於 [^0-9] 非數(shù)字 
 \s 等於 [ \t\n\x0B\f ] 空白字元 
 \S 等於 [^ \t\n\x0B\f ] 非空白字元 
 \w 等於 [a-zA-Z_0-9] 數(shù)字或是英文字 
  \W 等於 [^a-zA-Z_0-9] 非數(shù)字與英文字 
  
  ^ 表示每行的開頭
  $ 表示每行的結(jié)尾


snoics 2005-10-09 14:45 發(fā)表評(píng)論
]]>
java正則表達(dá)式; regular expression [轉(zhuǎn)]http://www.aygfsteel.com/snoics/articles/15054.htmlsnoicssnoicsSun, 09 Oct 2005 06:31:00 GMThttp://www.aygfsteel.com/snoics/articles/15054.htmlhttp://www.aygfsteel.com/snoics/comments/15054.htmlhttp://www.aygfsteel.com/snoics/articles/15054.html#Feedback0http://www.aygfsteel.com/snoics/comments/commentRss/15054.htmlhttp://www.aygfsteel.com/snoics/services/trackbacks/15054.html閱讀全文

snoics 2005-10-09 14:31 發(fā)表評(píng)論
]]>
正則表達(dá)式語法 [轉(zhuǎn)]http://www.aygfsteel.com/snoics/articles/15053.htmlsnoicssnoicsSun, 09 Oct 2005 06:28:00 GMThttp://www.aygfsteel.com/snoics/articles/15053.htmlhttp://www.aygfsteel.com/snoics/comments/15053.htmlhttp://www.aygfsteel.com/snoics/articles/15053.html#Feedback0http://www.aygfsteel.com/snoics/comments/commentRss/15053.htmlhttp://www.aygfsteel.com/snoics/services/trackbacks/15053.html 
一個(gè)正則表達(dá)式就是由普通字符(例如字符 a 到 z)以及特殊字符(稱為元字符)組成的文字模式。該模式描述在查找文字主體時(shí)待匹配的一個(gè)或多個(gè)字符串。正則表達(dá)式作為一個(gè)模板,將某個(gè)字符模式與所搜索的字符串進(jìn)行匹配。

這里有一些可能會(huì)遇到的正則表達(dá)式示例:

Visual Basic VBScript 匹配
Scripting Edition

/^[ t]*$/ "^[ t]*$" 匹配一個(gè)空白行。

/d{2}-d{5}/ "d{2}-d{5}" 驗(yàn)證一個(gè)ID號(hào)碼是否由一個(gè)2位字,一
個(gè)連字符以及一個(gè)5位數(shù)字組成。

/<(.*)>.*</1>/ "<(.*)>.*</1>" 匹配一個(gè) HTML 標(biāo)記。


下表是元字符及其在正則表達(dá)式上下文中的行為的一個(gè)完整列表:

字符 描述

將下一個(gè)字符標(biāo)記為一個(gè)特殊字符、或一個(gè)原義字符、或一個(gè) 后
向引用、或一個(gè)八進(jìn)制轉(zhuǎn)義符。例如,’n’ 匹配字符 "n"。’n’
匹配一個(gè)換行符。序列 ’’ 匹配 "" 而 "(" 則匹配 "("。

^ 匹配輸入字符串的開始位置。如果設(shè)置了 RegExp 對(duì)象的
Multiline 屬性,^ 也匹配 ’n’ 或 ’r’ 之后的位置。

$ 匹配輸入字符串的結(jié)束位置。如果設(shè)置了 RegExp 對(duì)象的
Multiline 屬性,$ 也匹配 ’n’ 或 ’r’ 之前的位置。

* 匹配前面的子表達(dá)式零次或多次。例如,zo* 能匹配 "z" 以及
"zoo"。 * 等價(jià)于{0,}。

+ 匹配前面的子表達(dá)式一次或多次。例如,’zo+’ 能匹配 "zo" 以
及 "zoo",但不能匹配 "z"。+ 等價(jià)于 {1,}。

? 匹配前面的子表達(dá)式零次或一次。例如,"do(es)?" 可以匹配
"do" 或 "does" 中的"do" 。? 等價(jià)于 {0,1}。

{n} n 是一個(gè)非負(fù)整數(shù)。匹配確定的 n 次。例如,’o{2}’ 不能匹配
"Bob" 中的 ’o’,但是能匹配 "food" 中的兩個(gè) o。

{n,} n 是一個(gè)非負(fù)整數(shù)。至少匹配n 次。例如,’o{2,}’ 不能匹配
"Bob" 中的 ’o’,但能匹配 "foooood" 中的所有 o?!痮{1,}’
等價(jià)于 ’o+’。’o{0,}’ 則等價(jià)于 ’o*’。

{n,m} m 和 n 均為非負(fù)整數(shù),其中n <= m。最少匹配 n 次且最多匹
配 m 次。劉, "o{1,3}" 將匹配 "fooooood" 中的前三個(gè)o。
’o{0,1}’等價(jià)于’o?’。請(qǐng)注意在逗號(hào)和兩個(gè)數(shù)之間不能有空格

? 當(dāng)該字符緊跟在任何一個(gè)其他限制符 (*, +, ?, {n}, {n,},
{n,m}) 后面時(shí),匹配模式是非貪婪的。非貪婪模式盡可能少的
匹配所搜索的字符串,而默認(rèn)的貪婪模式則盡可能多的匹配所搜
索的字符串。例如,對(duì)于字符串 "oooo",’o+?’ 將匹配單個(gè)
"o",而 ’o+’ 將匹配所有 ’o’。

. 匹配除 "n" 之外的任何單個(gè)字符。要匹配包括 ’n’ 在內(nèi)的任
何字符,請(qǐng)使用象 ’[.n]’ 的模式。

(pattern) 匹配pattern 并獲取這一匹配。所獲取的匹配可以從產(chǎn)生的
Matches 集合得到,在VBScript 中使用 SubMatches 集合,在
Visual Basic Scripting Edition 中則使用 $0…$9 屬性。要
匹配圓括號(hào)字符,請(qǐng)使用 ’(’ 或 ’)’。

(?:pattern) 匹配 pattern 但不獲取匹配結(jié)果,也就是說這是一個(gè)非獲取匹
配,不進(jìn)行存儲(chǔ)供以后使用。這在使用 "或" 字符 (|) 來組合
一個(gè)模式的各個(gè)部分是很有用。例如, ’industr(?:y|ies) 就
是一個(gè)比 ’industry|industries’ 更簡(jiǎn)略的表達(dá)式。

(?=pattern) 正向預(yù)查,在任何匹配 pattern 的字符串開始處匹配查找字符
串。這是一個(gè)非獲取匹配,也就是說,該匹配不需要獲取供以后
使用。例如,’Windows (?=95|98|NT|2000)’ 能匹配"Windows
2000"中的"Windows",但不能匹配"Windows3 .1"中"Windows"。
預(yù)查不消耗字符,也就是說,在一個(gè)匹配發(fā)生后,在最后一次匹
配之后立即開始下一次匹配的搜索,而不是從包含預(yù)查的字符之
后開始。

(?!pattern) 負(fù)向預(yù)查,在任何不匹配Negative lookahead matches the
search string at any point where a string not matching
pattern 的字符串開始處匹配查找字符串。這是一個(gè)非獲取匹
配,也就是說,該匹配不需要獲取供以后使用。例如’Windows
(?!95|98|NT|2000)’ 能匹配 "Windows 3.1" 中的 "Windows",
但不能匹配 "Windows 2000" 中的 "Windows"。預(yù)查不消耗字
符,也就是說,在一個(gè)匹配發(fā)生后,在最后一次匹配之后立即開
始下一次匹配的搜索,而不是從包含預(yù)查的字符之后開始

x|y 匹配 x 或 y。例如,’z|food’ 能匹配 "z" 或 "food"?!?z|f)
ood’ 則匹配 "zood" 或 "food"。

[xyz] 字符集合。匹配所包含的任意一個(gè)字符。例如, ’[abc]’ 可以
匹配 "plain" 中的 ’a’。

[^xyz] 負(fù)值字符集合。匹配未包含的任意字符。例如, ’[^abc]’ 可以
匹配 "plain" 中的’p’。

[a-z] 字符范圍。匹配指定范圍內(nèi)的任意字符。例如,’[a-z]’ 可以匹
配 ’a’ 到 ’z’ 范圍內(nèi)的任意小寫字母字符。

[^a-z] 負(fù)值字符范圍。匹配任何不在指定范圍內(nèi)的任意字符。例如,
’[^a-z]’ 可以匹配任何不在 ’a’ 到 ’z’ 范圍內(nèi)的任意字符。

b 匹配一個(gè)單詞邊界,也就是指單詞和空格間的位置。例如,
’erb’ 可以匹配"never" 中的 ’er’,但不能匹配 "verb" 中
的 ’er’。

B 匹配非單詞邊界?!痚rB’ 能匹配 "verb" 中的 ’er’,但不能匹
配 "never" 中的 ’er’。

cx 匹配由x指明的控制字符。例如, cM 匹配一個(gè) Control-M 或
回車符。 x 的值必須為 A-Z 或 a-z 之一。否則,將 c 視為一
個(gè)原義的 ’c’ 字符。

d 匹配一個(gè)數(shù)字字符。等價(jià)于 [0-9]。

D 匹配一個(gè)非數(shù)字字符。等價(jià)于 [^0-9]。

f 匹配一個(gè)換頁符。等價(jià)于 x0c 和 cL。

n 匹配一個(gè)換行符。等價(jià)于 x0a 和 cJ。

r 匹配一個(gè)回車符。等價(jià)于 x0d 和 cM。

s 匹配任何空白字符,包括空格、制表符、換頁符等等。等價(jià)于
[ fnrtv]。

S 匹配任何非空白字符。等價(jià)于 [^ fnrtv]。

t 匹配一個(gè)制表符。等價(jià)于 x09 和 cI。

v 匹配一個(gè)垂直制表符。等價(jià)于 x0b 和 cK。

w 匹配包括下劃線的任何單詞字符。等價(jià)于’[A-Za-z0-9_]’。

W 匹配任何非單詞字符。等價(jià)于 ’[^A-Za-z0-9_]’。

xn 匹配 n,其中 n 為十六進(jìn)制轉(zhuǎn)義值。十六進(jìn)制轉(zhuǎn)義值必須為確
定的兩個(gè)數(shù)字長(zhǎng)。例如, ’x41’ 匹配 "A"。’x041’ 則等價(jià)
于 ’x04’ & "1"。正則表達(dá)式中可以使用 ASCII 編碼。.

num 匹配 num,其中num是一個(gè)正整數(shù)。對(duì)所獲取的匹配的引用。
例如,’(.)1’ 匹配兩個(gè)連續(xù)的相同字符。

n 標(biāo)識(shí)一個(gè)八進(jìn)制轉(zhuǎn)義值或一個(gè)后向引用。如果 n 之前至少 n
個(gè)獲取的子表達(dá)式,則 n 為后向引用。否則,如果 n 為八進(jìn)制
數(shù)字 (0-7),則 n 為一個(gè)八進(jìn)制轉(zhuǎn)義值。

nm 標(biāo)識(shí)一個(gè)八進(jìn)制轉(zhuǎn)義值或一個(gè)后向引用。如果 nm 之前至少有
is preceded by at least nm 個(gè)獲取得子表達(dá)式,則 nm 為后
向引用。如果 nm 之前至少有 n 個(gè)獲取,則 n 為一個(gè)后跟文
字 m 的后向引用。如果前面的條件都不滿足,若 n 和 m 均為
八進(jìn)制數(shù)字 (0-7),則 nm 將匹配八進(jìn)制轉(zhuǎn)義值 nm。

nml 如果 n 為八進(jìn)制數(shù)字 (0-3),且 m 和 l 均為八進(jìn)制數(shù)字 (0-
7),則匹配八進(jìn)制轉(zhuǎn)義值 nml。

un 匹配 n,其中 n 是一個(gè)用四個(gè)十六進(jìn)制數(shù)字表示的Unicode字
符。例如, u00A9 匹配版權(quán)符號(hào) (?)。


snoics 2005-10-09 14:28 發(fā)表評(píng)論
]]>
正則表達(dá)式高級(jí)學(xué)習(xí)技巧 [轉(zhuǎn)]http://www.aygfsteel.com/snoics/articles/15052.htmlsnoicssnoicsSun, 09 Oct 2005 06:26:00 GMThttp://www.aygfsteel.com/snoics/articles/15052.htmlhttp://www.aygfsteel.com/snoics/comments/15052.htmlhttp://www.aygfsteel.com/snoics/articles/15052.html#Feedback0http://www.aygfsteel.com/snoics/comments/commentRss/15052.htmlhttp://www.aygfsteel.com/snoics/services/trackbacks/15052.html 前言
  Regular Expressions(正則表達(dá)式,以下用RE稱呼)對(duì)小弟來說一直都是神密的地帶,看到一些網(wǎng)絡(luò)上的大大,簡(jiǎn)單用RE就決解了某些文字的問題,小弟便興起了學(xué)一學(xué)RE的想法,但小弟天生就比較懶一些,總希望看有沒有些快速學(xué)習(xí)的方式,于是小弟又請(qǐng)出Google大神,藉由祂的神力,小弟在網(wǎng)絡(luò)上找到了Jim Hollenhorst先生的文章,經(jīng)過了閱讀,小弟覺得真是不錯(cuò),所以就做個(gè)小心得報(bào)告,跟Move-to.Net的朋友分享,希望能為各位大大帶來一丁點(diǎn)在學(xué)習(xí)RE時(shí)的幫助。Jim Hollenhorst大大文章之網(wǎng)址如下,有需要的大大可直接連結(jié)。

  The 30 Minute Regex Tutorial By Jim Hollenhorst

  http://www.codeproject.com/useritems/RegexTutorial.asp

  什么是RE?
  想必各位大大在做文件查找的時(shí)侯都有使用過萬用字符”*”,比如說想查找在Windows目錄下所有的Word文件時(shí),你可能就會(huì)用”*.doc”這樣的方式來做查找,因?yàn)椤?”所代表的是任意的字符。RE所做的就是類似這樣的功能,但其功能更為強(qiáng)大。

  寫程序時(shí),常需要比對(duì)字符串是否符合特定樣式,RE最主要的功能就是來描述這特定的樣式,因此可以將RE視為特定樣式的描述式,舉個(gè)例子來說,”w+”所代表的就是任何字母與數(shù)字所組成的非空字符串(non-null string)。在.NET framework中提供了非常強(qiáng)大的類別庫,藉此可以很輕易的使用RE來做文字的查找與取代、對(duì)復(fù)雜標(biāo)頭的譯碼及驗(yàn)證文字等工作。

  學(xué)習(xí)RE最好的方式就是藉由例子親自來做做看。Jim Hollenhorst大大也提供了一個(gè)工具程序Expresso(來杯咖啡吧),來幫助我們學(xué)習(xí)RE,下載的網(wǎng)址是http://www.codeproject.com/useritems/RegexTutorial/ExpressoSetup2_1C.zip。

  接下來,就讓我們來體驗(yàn)一些例子吧。

  一些簡(jiǎn)單的例子
  假設(shè)要查找文章中Elvis后接有alive的文字符串的話,使用RE可能會(huì)經(jīng)過下列的過程,括號(hào)是所下RE的意思:

  1. elvis (查找elvis)

  上述代表所要查找的字符順序?yàn)閑lvis。在.NET中可以設(shè)定乎略字符的大小寫,所以”Elvis”、”ELVIS”或者是”eLvIs”都是符合1所下的RE。但因?yàn)檫@只管字符出現(xiàn)的順序?yàn)閑lvis,所以pelvis也是符合1所下的RE??梢杂?的RE來改進(jìn)。

  2. belvisb (將elvis視為一整體的字查找,如elvis、Elvis乎略字符大小寫時(shí))
“b”在RE中有特別的意思,在上述的例子中所指的就是字的邊界,所以belvisb用b把elvis的前后邊界界定出來,也就是要elvis這個(gè)字。

  假設(shè)要將同一行里elvis后接有alive的文字符串找出來,此時(shí)就會(huì)用到另外二個(gè)特別意義的字符”.”及”*”?!?”所代表就是除了換行字符的任意字符,而”*”所代表的是重復(fù)*之前項(xiàng)目直到找到符合RE的字符串。所以”.*”所指的就是除了換行字符外的任意數(shù)目的字符數(shù)。所以查找同一行里elvis后接有alive的文字符串找出來,則可下如3之RE。

  3. belvisb.*baliveb (查找elvis后面接有alive的文字符串,如elvis is alive)

  用簡(jiǎn)單之特別字符就可以組成功能強(qiáng)大的RE,但也發(fā)現(xiàn)當(dāng)使用越來越多的特別字符時(shí),RE就會(huì)越來越難看得懂了。


再看看另外的例子
  組成有效的電話號(hào)碼

  假使要從網(wǎng)頁上收集顧客格式為xxx-xxxx的7位數(shù)字的電話號(hào)碼,其中x是數(shù)字,RE可能會(huì)這樣寫。

  4. bddd-dddd (查找七位數(shù)字之電話號(hào)碼,如123-1234)
  每一個(gè)d代表一個(gè)數(shù)字?!?”則是一般的連字符號(hào),為避免太多重復(fù)的d,RE可以改寫成如5的方式。

  5. bd{3}-d{4} (查找七位數(shù)字電話號(hào)碼較好的方法,如123-1234)
  在d后的{3},代表重復(fù)前一個(gè)項(xiàng)目三次,也就是相等于ddd。

  RE的學(xué)習(xí)及測(cè)試工具 Expresso

  因?yàn)镽E不易閱讀及使用者容易會(huì)下錯(cuò)RE的特性,Jim大大開發(fā)了一個(gè)工具軟件Expresso,用來幫助使用者學(xué)習(xí)及測(cè)試RE,除了上面所述的網(wǎng)址之外,也可以上Ultrapico網(wǎng)站(http://www.Ultrapico.com)。安裝完Expresso后,在Expression Library中,Jim大大把文章的例子都建立在其中,可以邊看文章邊測(cè)試,也可以試著修改范例所下的RE,馬上可以看到結(jié)果,小弟覺得非常好用。各位大大可以試試。

  .NET中RE的基礎(chǔ)概念
  特殊字符

  有些字符有特別的意義,比如之前所看到的”b”、”.”、”*”、”d”等?!眘”所代表的是任意空格符,比如說spaces、tabs、newlines等.?!眞”代表是任意字母或數(shù)字字符。

  再看一些例子吧
  6. baw*b (查找a開頭的字,如able)
  這RE描述要查找一個(gè)字的開始邊界(b),再來是字母”a”,再加任意數(shù)目的字母數(shù)字(w*),再接結(jié)束這個(gè)字的結(jié)束邊界(b)。

  7. d+ (查找數(shù)字字符串)
  “+”和”*”非常相似,除了+至少要重復(fù)前面的項(xiàng)目一次。也就是說至少有一個(gè)數(shù)字。

  8. bw{6}b (查找六個(gè)字母數(shù)字的字,如ab123c)

  下表為RE常用的特殊字符

  . 除了換行字符的任意字符
  w 任意字母數(shù)字字符
  s 任意空格符
  d 任意數(shù)字字符
  b 界定字的邊界
  ^ 文章的開頭,如”^The'' 用以表示出現(xiàn)于文章開頭的字符串為”The”
  $ 文章的結(jié)尾,如”End$”用以表示出現(xiàn)在文章的結(jié)尾為”End”
  特殊字符”^”及”$”是用來查找某些字必需是文章的開頭或結(jié)尾,這在驗(yàn)證輸入是否符合某一樣式時(shí)特別用有,比如說要驗(yàn)證七位數(shù)字的電話號(hào)碼,可能會(huì)輸入如下9的RE。

  9. ^d{3}-d{4}$ (驗(yàn)證七位數(shù)字之電話號(hào)碼)

  這和第5個(gè)RE相同,但其前后都無其它的字符,也就是整串字符串只有這七個(gè)數(shù)字的電話號(hào)碼。在.NET中如果設(shè)定Multiline這個(gè)選項(xiàng),則”^”和”$”會(huì)每行進(jìn)行比較,只要某行的開頭結(jié)尾符合RE即可,而不是整個(gè)文章字符串做一次比較。

  轉(zhuǎn)意字符(Escaped characters)

  有時(shí)可能會(huì)需要”^”、”$”單純的字面意義(literal meaning)而不要將它們當(dāng)成特殊字符,此時(shí)””字符就是用來移除特殊字符特別意義的字符,因此”^”、”.”、””所代表的就是”^”、”.”、””的字面意義。

  重復(fù)前述項(xiàng)目

  在前面看過”{3}”及”*”可以用來重復(fù)前述字符,之后我們會(huì)看到如何用同樣的語法重復(fù)整個(gè)次描述(subexpressions)。下表是使用重復(fù)前述項(xiàng)目的一些方式。

  * 重復(fù)任意次數(shù)
  + 重復(fù)至少一次
  ? 重復(fù)零次或一次
  {n} 重復(fù)n次
  {n,m} 重復(fù)至少n次,但不超過m次
  {n,} 重復(fù)至少n次

  再來試一些例子吧

  10. bw{5,6}b (查找五個(gè)或六個(gè)字母數(shù)字字符的字,如as25d、d58sdf等)
  11. bd{3}sd{3}-d{4} (查找十個(gè)數(shù)字的電話號(hào)碼,如800 123-1234)
  12. d{3}-d{2}-d{4} (查找社會(huì)保險(xiǎn)號(hào)碼,如 123-45-6789)
  13. ^w* (每行或整篇文章的第一個(gè)字)
  在Espresso可試試有Multiline和沒Multiline的不同。

  匹配某范圍的字符

  有時(shí)需要查找某些特定的字符時(shí)怎么辨?這時(shí)中括號(hào)”[]”就派上了用場(chǎng)。因此[aeiou]所要查找的是”a”、”e”、”i”、”o”、”u”這些元音,[.?!]所要查找的是”.”、”?”、”!”這些符號(hào),在中括號(hào)中的特殊字符的特別意義都會(huì)被移除,也就是解譯成單純的字面意義。也可以指定某些范圍的字符,如”[a-z0-9]”,所指的就是任意小寫字母或任意數(shù)字。

  接下來再看一個(gè)比較初復(fù)雜查找電話號(hào)碼的RE例子

  14. (?d{3}[( ] s?d{3}[- ]d{4} (查找十位數(shù)字之電話號(hào)碼,如(080) 333-1234 )

  這樣的RE可查找出較多種格式的電話號(hào)碼,如(080) 123-4567、511 254 6654等?!??”代表一個(gè)或零個(gè)左小括號(hào)”(“,而”[( ]”代表查找一個(gè)右小括號(hào)”)”或空格符,”s?”指一個(gè)或零個(gè)空格符組。但這樣的RE會(huì)將類似”800) 45-3321”這樣的電話找出來,也就是括號(hào)沒有對(duì)稱平衡的問題,之后會(huì)學(xué)到擇一(alternatives)來決解這樣的問題。

  不包含在某特定字符組里(Negation)

  有時(shí)需要查找在包含在某特定字符組里的字符,下表說明如何做類似這樣的描述。

  W 不是字母數(shù)字的任意字符
  S 不是空格符的任意字符
  D 不是數(shù)字字符的任意字符
  B 不在字邊界的位置
  [^x] 不是x的任意字符
  [^aeiou] 不是a、e、i、o、u的任意字符

  15. S+ (不包含空格符的字符串)

  擇一(Alternatives)

  有時(shí)會(huì)需要查找?guī)讉€(gè)特定的選擇,此時(shí)”|”這個(gè)特殊字符就派上用場(chǎng)了,舉例來說,要查找五個(gè)數(shù)字及九個(gè)數(shù)字(有”-”號(hào))的郵政編碼。

  16. bd{5}-d{4}b|bd{5}b (查找五個(gè)數(shù)字及九個(gè)數(shù)字(有”-”號(hào))的郵政編碼)

  在使用Alternatives時(shí)需要注意的是前后的次序,因?yàn)镽E在Alternatives中會(huì)優(yōu)先選擇符合最左邊的項(xiàng)目,16中,如果把查找五個(gè)數(shù)字的項(xiàng)目放在前面,則這RE只會(huì)找到五個(gè)數(shù)字的郵政編碼。了解了擇一,可將14做更好的修正。

  17. ((d{3})|d{3})s?d{3}[- ]d{4} (十個(gè)數(shù)字的電話號(hào)碼)

  群組(Grouping)

  括號(hào)可以用來介定一個(gè)次描述,經(jīng)由次描述的介定,可以針對(duì)次描述做重復(fù)或及他的處理。

  18. (d{1,3}.){3}d{1,3} (尋找網(wǎng)絡(luò)地址的簡(jiǎn)單RE)

  此RE的意思第一個(gè)部分(d{1,3}.){3},所指的是,數(shù)字最小一位最多三位,并且后面接有”.”符號(hào),此類型的共有三個(gè),之后再接一到三位的數(shù)字,也就是如192.72.28.1這樣的數(shù)字。

  但這樣會(huì)有個(gè)缺點(diǎn),因?yàn)榫W(wǎng)絡(luò)地址數(shù)字最多只到255,但上述的RE只要是一到三位的數(shù)字都是符合的,所以這需要讓比較的數(shù)字小于256才行,但只單獨(dú)使用RE并無法做這樣的比較。在19中使用擇一來將地址的限制在所需要的范圍內(nèi),也就是0到255。

  19. ((2[0-4]d|25[0-5]|[01]?dd?).){3}(2[0-4]d|25[0-5]|[01]?dd?) (尋找網(wǎng)絡(luò)地址)

  有沒有發(fā)覺RE越來越像外星人說的話了?就以簡(jiǎn)單的尋找網(wǎng)絡(luò)地址,直接看RE都滿難理解的哩。

  Expresso Analyzer View

  Expresso提供了一個(gè)功能,它可以將所下的RE變成樹狀的說明,一組組的分開說明,提供了一個(gè)好的除錯(cuò)環(huán)境。其它的功能,如部分符合(Partial Match只查找反白R(shí)E的部分)及除外符合(Exclude Match只不查找反白R(shí)E的部分)就留給各位大大試試啰。

  當(dāng)次描述用括號(hào)群組起來時(shí),符合次描述的文字可用在之后的程序處理或RE本身。在預(yù)設(shè)的情型下,所符合的群組是由數(shù)字命名,由1開始,由順序是由左至右,這自動(dòng)群組命名,可在Expresso中的skeleton view或result view中看到。

  Backreference是用來查找群組中抓取的符合文字所相同的文字。舉例來說”1”所指符合群組1所抓取的文字。

  20. b(w+)bs*1b (尋找重復(fù)字,此處說的重復(fù)是指同樣的字,中間有空白隔開如dog dog這樣的字)
(w+)會(huì)抓取至少一個(gè)字符的字母或數(shù)字的字,并將它命名為群組1,之后是查找任意空格符,再接和群組1相同的文字。

  如果不喜歡群組自動(dòng)命名的1,也可以自行命名,以上述例子為例,(w+)改寫為(?<Word>w+),這就是將所抓取的群組命名為Word,Backreference就要改寫成為k<Word>
21. b(?<Word>w+)bs*k<Word>b (使用自行命名群組抓取重復(fù)字)

  使用括號(hào)還有許多特別的語法元素,比較通用的列表如下:

  抓取(Captures) 
  (exp) 符合exp并抓取它進(jìn)自動(dòng)命名的群組
  (?<name>exp) 符合exp并抓取它進(jìn)命名的群組name
  (?:exp) 符合exp,不抓取它
  Lookarounds 
  (?=exp) 符合字尾為exp的文字
  (?<=exp) 符合前綴為exp的文字
  (?!exp) 符合后面沒接exp字尾的文字
  (?<!exp) 符合前面沒接exp前綴的文字
  批注Comment 
  (?#comment) 批注

  Positive Lookaround

  接下來要談的是lookahead及l(fā)ookbehind assertions。它們所查找的是目前符合之前或之后的文字,并不包含目前符合本身。這些就如同”^”及”b”特殊字符,本身并不會(huì)對(duì)應(yīng)任何文字(用來界定位置),也因此稱做是zero-width assertions,看些例子也許會(huì)清楚些。

  (?=exp)是一個(gè)”zero-width positive lookahead assertion”。它指的就是符合字尾為exp的文字,但不包含exp本身。

  22. bw+(?=ingb) (字尾為ing的字,比如說filling所符合的就是fill)
(?<=exp)是一個(gè)”zero-width positive lookbehind assertion”。它指的就是符合前綴為exp的文字,但不包含exp本身。

  23. (?<=bre)w+b (前綴為re的字,比如說repeated所符合的就是peated)
  24. (?<=d)d{3}b (在字尾的三位數(shù)字,且之前接一位數(shù)字)
  25. (?<=s)w+(?=s) (由空格符分隔開的字母數(shù)字字符串)

  Negative Lookaround

  之前有提到,如何查找一個(gè)非特定或非在特定群組的字符。但如果只是要驗(yàn)證某字符不存在而不要對(duì)應(yīng)這些字符進(jìn)來呢?舉個(gè)例子來說,假設(shè)要查找一個(gè)字,它的字母里有q但接下來的字母不是u,可以用下列的RE來做。

  26. bw*q[^u]w*b (一個(gè)字,其字母里有q但接下來的字母不是u)

  這樣的RE會(huì)有一個(gè)問題,因?yàn)閇^u]要對(duì)應(yīng)一個(gè)字符,所以若q是字的最后一個(gè)字母,[^u]這樣的下法就會(huì)將空格符對(duì)應(yīng)下去,結(jié)果就有可能會(huì)符合二個(gè)字,比如說”Iraq haha”這樣的文字。使用Negative Lookaround就能解決這樣的問題。

  27. bw*q(?!u)w*b (一個(gè)字,其字母里有q但接下來的字母不是u)
  這是”zero-width negative lookahead assertion”。

  28. d{3}(?!d) (三個(gè)位的數(shù)字,其后不接一個(gè)位數(shù)字)

  同樣的,可以使用(?<!exp),”zero-width negative lookbehind assertion”,來符合前面沒接exp前綴的文字符串。

  29. (?<![a-z ])w{7} (七個(gè)字母數(shù)字的字符串,其前面沒接字母或空格)

  30. (?<=<(w+)>).*(?=</1>) (HTML卷標(biāo)間的文字)
  這使用lookahead及l(fā)ookbehind assertion來取出HTML間的文字,不包括HTML卷標(biāo)。

  請(qǐng)批注(Comments Please)
  括號(hào)還有個(gè)特殊的用途就是用來包住批注,語法為”(?#comment)”,若設(shè)定”Ignore Pattern Whitespace”選項(xiàng),則RE中的空格符當(dāng)RE使用時(shí)會(huì)乎略。此選項(xiàng)設(shè)定時(shí),”#”之后的文字會(huì)乎略。

  31. HTML卷標(biāo)間的文字,加上批注

  (?<=   #查找前綴,但不包含它
  <(w+)> #HTML標(biāo)簽
  )       #結(jié)束查找前綴
  .*      #符合任何文字
  (?=     #查找字尾,但不包含它
  </1>  #符合所抓取群組1之字符串,也就是前面小括號(hào)的HTML標(biāo)簽
  )       #結(jié)束查找字尾

  尋找最多字符的字及最少字符的字(Greedy and Lazy)
  當(dāng)RE下要查找一個(gè)范圍的重復(fù)時(shí)(如”.*”),它通常會(huì)尋找最多字符的符合字,也就是Greedy matching。舉例來說。

  32. a.*b  (開始為a結(jié)束為b的最多字符的符合字)

  若有一字符串是”aabab”,使用上述RE所得到的符合字符串就是”aabab”,因?yàn)檫@是尋找最多字符的字。有時(shí)希望是符合最少字符的字也就是lazy matching。只要將重復(fù)前述項(xiàng)目的表加上問號(hào)(?)就可以把它們?nèi)孔兂蒷azy matching。因此”*?”代表的就是重復(fù)任意次數(shù),但是使用最少重復(fù)的次數(shù)來符合。舉個(gè)例子來說:

  33. a.*?b (開始為a結(jié)束為b的最少字符的符合字)

  若有一字符串是”aabab”,使用上述RE第一個(gè)所得到的符合字符串就是”aab”再來是”ab”,因?yàn)檫@是尋找最少字符的字。

  *? 重復(fù)任意次數(shù),最少重復(fù)次數(shù)為原則
  +? 重復(fù)至少一次,最少重復(fù)次數(shù)為原則
  ?? 重復(fù)零次或一次,最少重復(fù)次數(shù)為原則
  {n,m}? 重復(fù)至少n次,但不超過m次,最少重復(fù)次數(shù)為原則
  {n,}? 重復(fù)至少n次,最少重復(fù)次數(shù)為原則

還有什么沒提到呢?

  到目前為止,已經(jīng)提到了許多建立RE的元素,當(dāng)然還有許多元素沒有提到,下表整理了一些沒提到的元素,在最左邊的字段的數(shù)字是說明在Expresso中的例子。

  # 語法 說明

  a Bell 字符
  b 通常是指字的邊界,在字符組里所代表的就是backspace
  t Tab

  34 r Carriage return

  v Vertical Tab
  f From feed

  35 n New line
   e Escape

  36 nnn ASCII八位碼為nnn的字符

  37 xnn 十六位碼為nn的字符

  38 unnnn Unicode為nnnn的字符

  39 cN Control N字符,舉例來說Ctrl-M是cM

  40 A 字符串的開始(和^相似,但不需籍由multiline選項(xiàng))

  41 Z 字符串的結(jié)尾
  z 字符串的結(jié)尾

  42 G 目前查找的開始

  43 p{name} Unicode 字符組名稱為name的字符,比如說p{Lowercase_Letter} 所指的就是小寫字
  (?>exp) Greedy次描述,又稱之為non-backtracking次描述。這只符合一次且不采backtracking。

  44 (?<x>-<y>exp)

  or (?-<y>exp) 平衡群組。雖復(fù)雜但好用。它讓已命名的抓取群組可以在堆棧中操作使用。(小弟對(duì)這個(gè)也是不太懂哩)

  45 (?im-nsx:exp) 為次描述exp更改RE選項(xiàng),比如(?-i:Elvis)就是把Elvis大乎略大小寫的選項(xiàng)關(guān)掉

  46 (?im-nsx) 為之后的群組更改RE選項(xiàng)。
  (?(exp)yes|no) 次描述exp視為zero-width positive lookahead。若此時(shí)有符合,則yes次描述為下一個(gè)符合標(biāo)的,若否,則no 次描述為下一個(gè)符合標(biāo)的。
  (?(exp)yes) 和上述相同但無no次描述
  (?(name)yes|no) 若name群組為有效群組名稱,則yes次描述為下一個(gè)符合標(biāo)的,若否,則no 次描述為下一個(gè)符合標(biāo)的。

  47 (?(name)yes) 和上述相同但無no次描述

  結(jié)論
  經(jīng)過了一連串的例子,及Expresso的幫忙,相信各位大大對(duì)RE有個(gè)基本的了解,網(wǎng)絡(luò)上當(dāng)然有許多有關(guān)于RE的文章,如果各位大大有興趣http://www.codeproject.com 還有許多關(guān)于RE的相關(guān)文章。若大大對(duì)書有興趣的話,Jeffrey Friedl的Mastering Regular Expressions很多大大都有推(小弟還沒拜讀)。希望籍由這樣的心得報(bào)告,能讓對(duì)RE有興趣的大大能縮短學(xué)習(xí)曲線,當(dāng)然這是小弟第一次接觸RE,若文章中有什么錯(cuò)誤或說明的不好的地方,可要請(qǐng)各位大大體諒,并請(qǐng)各位大大將需要修正的地方mail給小弟,小弟會(huì)非常感謝各位大大。

snoics 2005-10-09 14:26 發(fā)表評(píng)論
]]>
正則表達(dá)式之道 [轉(zhuǎn)]http://www.aygfsteel.com/snoics/articles/15046.htmlsnoicssnoicsSun, 09 Oct 2005 06:04:00 GMThttp://www.aygfsteel.com/snoics/articles/15046.htmlhttp://www.aygfsteel.com/snoics/comments/15046.htmlhttp://www.aygfsteel.com/snoics/articles/15046.html#Feedback0http://www.aygfsteel.com/snoics/comments/commentRss/15046.htmlhttp://www.aygfsteel.com/snoics/services/trackbacks/15046.html

原著:Steve Mansour
sman@scruznet.com
Revised: June 5, 1999
(copied by jm /at/ jmason.org from http://www.scruz.net/%7esman/regexp.htm, after the original disappeared! )

翻譯:Neo Lee
neo.lee@gmail.com
2004年10月16日


英文版原文

譯者按:原文因?yàn)槟甏眠h(yuǎn),文中很多鏈接早已過期(主要是關(guān)于vi、sed等工具的介紹和手冊(cè)),本譯文中已將此類鏈接刪除,如需檢查這些鏈接可以查看上面鏈接的原文。除此之外基本照原文直譯,括號(hào)中有“譯者按”的部分是譯者補(bǔ)充的說明。如有內(nèi)容方面的問題請(qǐng)直接和Steve Mansor聯(lián)系,當(dāng)然,如果你只寫中文,也可以和我聯(lián)系。


目 錄

什么是正則表達(dá)式
范例
   簡(jiǎn)單
   中級(jí)(神奇的咒語)
   困難(不可思議的象形文字)
不同工具中的正則表達(dá)式

 


什么是正則表達(dá)式

一個(gè)正則表達(dá)式,就是用某種模式去匹配一類字符串的一個(gè)公式。很多人因?yàn)樗鼈兛瓷先ケ容^古怪而且復(fù)雜所以不敢去使用——很不幸,這篇文章也不能夠改變這一點(diǎn),不過,經(jīng)過一點(diǎn)點(diǎn)練習(xí)之后我就開始覺得這些復(fù)雜的表達(dá)式其實(shí)寫起來還是相當(dāng)簡(jiǎn)單的,而且,一旦你弄懂它們,你就能把數(shù)小時(shí)辛苦而且易錯(cuò)的文本處理工作壓縮在幾分鐘(甚至幾秒鐘)內(nèi)完成。正則表達(dá)式被各種文本編輯軟件、類庫(例如Rogue Wave的tools.h++)、腳本工具(像awk/grep/sed)廣泛的支持,而且像Microsoft的Visual C++這種交互式IDE也開始支持它了。

我們將在如下的章節(jié)中利用一些例子來解釋正則表達(dá)式的用法,絕大部分的例子是基于vi中的文本替換命令和grep文件搜索命令來書寫的,不過它們都是比較典型的例子,其中的概念可以在sed、awk、perl和其他支持正則表達(dá)式的編程語言中使用。你可以看看不同工具中的正則表達(dá)式這一節(jié),其中有一些在別的工具中使用正則表達(dá)式的例子。還有一個(gè)關(guān)于vi中文本替換命令(s)的簡(jiǎn)單說明附在文后供參考。

正則表達(dá)式基礎(chǔ)

正則表達(dá)式由一些普通字符和一些元字符(metacharacters)組成。普通字符包括大小寫的字母和數(shù)字,而元字符則具有特殊的含義,我們下面會(huì)給予解釋。

在最簡(jiǎn)單的情況下,一個(gè)正則表達(dá)式看上去就是一個(gè)普通的查找串。例如,正則表達(dá)式"testing"中沒有包含任何元字符,,它可以匹配"testing"和"123testing"等字符串,但是不能匹配"Testing"。

要想真正的用好正則表達(dá)式,正確的理解元字符是最重要的事情。下表列出了所有的元字符和對(duì)它們的一個(gè)簡(jiǎn)短的描述。

元字符   描述


.
匹配任何單個(gè)字符。例如正則表達(dá)式r.t匹配這些字符串:rat、rut、r t,但是不匹配root。 
$
匹配行結(jié)束符。例如正則表達(dá)式weasel$ 能夠匹配字符串"He's a weasel"的末尾,但是不能匹配字符串"They are a bunch of weasels."。 
^
匹配一行的開始。例如正則表達(dá)式^When in能夠匹配字符串"When in the course of human events"的開始,但是不能匹配"What and When in the"。
*
匹配0或多個(gè)正好在它之前的那個(gè)字符。例如正則表達(dá)式.*意味著能夠匹配任意數(shù)量的任何字符。
這是引用府,用來將這里列出的這些元字符當(dāng)作普通的字符來進(jìn)行匹配。例如正則表達(dá)式$被用來匹配美元符號(hào),而不是行尾,類似的,正則表達(dá)式.用來匹配點(diǎn)字符,而不是任何字符的通配符。
[ ] 
[c1-c2]
[^c1-c2]
匹配括號(hào)中的任何一個(gè)字符。例如正則表達(dá)式r[aou]t匹配rat、rotrut,但是不匹配ret??梢栽诶ㄌ?hào)中使用連字符-來指定字符的區(qū)間,例如正則表達(dá)式[0-9]可以匹配任何數(shù)字字符;還可以制定多個(gè)區(qū)間,例如正則表達(dá)式[A-Za-z]可以匹配任何大小寫字母。另一個(gè)重要的用法是“排除”,要想匹配除了指定區(qū)間之外的字符——也就是所謂的補(bǔ)集——在左邊的括號(hào)和第一個(gè)字符之間使用^字符,例如正則表達(dá)式[^269A-Z] 將匹配除了2、6、9和所有大寫字母之外的任何字符。
< >
匹配詞(word)的開始(<)和結(jié)束(>)。例如正則表達(dá)式<the能夠匹配字符串"for the wise"中的"the",但是不能匹配字符串"otherwise"中的"the"。注意:這個(gè)元字符不是所有的軟件都支持的。
( )
將 ( 和 ) 之間的表達(dá)式定義為“組”(group),并且將匹配這個(gè)表達(dá)式的字符保存到一個(gè)臨時(shí)區(qū)域(一個(gè)正則表達(dá)式中最多可以保存9個(gè)),它們可以用 19 的符號(hào)來引用。
|
將兩個(gè)匹配條件進(jìn)行邏輯“或”(Or)運(yùn)算。例如正則表達(dá)式(him|her) 匹配"it belongs to him"和"it belongs to her",但是不能匹配"it belongs to them."。注意:這個(gè)元字符不是所有的軟件都支持的。
+
匹配1或多個(gè)正好在它之前的那個(gè)字符。例如正則表達(dá)式9+匹配9、99、999等。注意:這個(gè)元字符不是所有的軟件都支持的。
?
匹配0或1個(gè)正好在它之前的那個(gè)字符。注意:這個(gè)元字符不是所有的軟件都支持的。
{i}
{i,j}
匹配指定數(shù)目的字符,這些字符是在它之前的表達(dá)式定義的。例如正則表達(dá)式A[0-9]{3} 能夠匹配字符"A"后面跟著正好3個(gè)數(shù)字字符的串,例如A123、A348等,但是不匹配A1234。而正則表達(dá)式[0-9]{4,6} 匹配連續(xù)的任意4個(gè)、5個(gè)或者6個(gè)數(shù)字字符。注意:這個(gè)元字符不是所有的軟件都支持的。

 


最簡(jiǎn)單的元字符是點(diǎn),它能夠匹配任何單個(gè)字符(注意包括新行符)。假定有個(gè)文件test.txt包含以下幾行內(nèi)容:

    he is a rat
    he is in a rut
    the food is Rotten
    I like root beer
我們可以使用grep命令來測(cè)試我們的正則表達(dá)式,grep命令使用正則表達(dá)式去嘗試匹配指定文件的每一行,并將至少有一處匹配表達(dá)式的所有行顯示出來。命令
    grep r.t test.txt
在test.txt文件中的每一行中搜索正則表達(dá)式r.t,并打印輸出匹配的行。正則表達(dá)式r.t匹配一個(gè)r接著任何一個(gè)字符再接著一個(gè)t。所以它將匹配文件中的ratrut,而不能匹配Rotten中的Rot,因?yàn)檎齽t表達(dá)式是大小寫敏感的。要想同時(shí)匹配大寫和小寫字母,應(yīng)該使用字符區(qū)間元字符(方括號(hào))。正則表達(dá)式[Rr]能夠同時(shí)匹配Rr。所以,要想匹配一個(gè)大寫或者小寫的r接著任何一個(gè)字符再接著一個(gè)t就要使用這個(gè)表達(dá)式:[Rr].t

要想匹配行首的字符要使用抑揚(yáng)字符(^)——又是也被叫做插入符。例如,想找到text.txt中行首"he"打頭的行,你可能會(huì)先用簡(jiǎn)單表達(dá)式he,但是這會(huì)匹配第三行的the,所以要使用正則表達(dá)式^he,它只匹配在行首出現(xiàn)的h

有時(shí)候指定“除了×××都匹配”會(huì)比較容易達(dá)到目的,當(dāng)抑揚(yáng)字符(^)出現(xiàn)在方括號(hào)中是,它表示“排除”,例如要匹配he ,但是排除前面是t or s的情性(也就是theshe),可以使用:[^st]he。

可以使用方括號(hào)來指定多個(gè)字符區(qū)間。例如正則表達(dá)式[A-Za-z]匹配任何字母,包括大寫和小寫的;正則表達(dá)式[A-Za-z][A-Za-z]* 匹配一個(gè)字母后面接著0或者多個(gè)字母(大寫或者小寫)。當(dāng)然我們也可以用元字符+做到同樣的事情,也就是:[A-Za-z]+ ,和[A-Za-z][A-Za-z]*完全等價(jià)。但是要注意元字符+ 并不是所有支持正則表達(dá)式的程序都支持的。關(guān)于這一點(diǎn)可以參考后面的正則表達(dá)式語法支持情況。

要指定特定數(shù)量的匹配,要使用大括號(hào)(注意必須使用反斜杠來轉(zhuǎn)義)。想匹配所有1001000的實(shí)例而排除1010000,可以使用:10{2,3},這個(gè)正則表達(dá)式匹配數(shù)字1后面跟著2或者3個(gè)0的模式。在這個(gè)元字符的使用中一個(gè)有用的變化是忽略第二個(gè)數(shù)字,例如正則表達(dá)式0{3,} 將匹配至少3個(gè)連續(xù)的0。

簡(jiǎn)單的例子

這里有一些有代表性的、比較簡(jiǎn)單的例子。

vi 命令 作用


:%s/ */ /g 把一個(gè)或者多個(gè)空格替換為一個(gè)空格。
:%s/ *$// 去掉行尾的所有空格。
:%s/^/ / 在每一行頭上加入一個(gè)空格。
:%s/^[0-9][0-9]* // 去掉行首的所有數(shù)字字符。
:%s/b[aeio]g/bug/g 將所有的bagbeg、bigbog改為bug。 
:%s/t([aou])g/h1t/g 將所有tag、togtug分別改為hat、hothug(注意用group的用法和使用1引用前面被匹配的字符)。

中級(jí)的例子(神奇的咒語)

例1

將所有方法foo(a,b,c)的實(shí)例改為foo(b,a,c)。這里a、b和c可以是任何提供給方法foo()的參數(shù)。也就是說我們要實(shí)現(xiàn)這樣的轉(zhuǎn)換:

之前   之后
foo(10,7,2) foo(7,10,2)
foo(x+13,y-2,10) foo(y-2,x+13,10)
foo( bar(8), x+y+z, 5) foo( x+y+z, bar(8), 5)

下面這條替換命令能夠?qū)崿F(xiàn)這一魔法:

    :%s/foo(([^,]*),([^,]*),([^)]*))/foo(2,1,3)/g

現(xiàn)在讓我們把它打散來加以分析。寫出這個(gè)表達(dá)式的基本思路是找出foo()和它的括號(hào)中的三個(gè)參數(shù)的位置。第一個(gè)參數(shù)是用這個(gè)表達(dá)式來識(shí)別的::([^,]*),我們可以從里向外來分析它: 

[^,]   除了逗號(hào)之外的任何字符
[^,]* 0或者多個(gè)非逗號(hào)字符
([^,]*) 將這些非逗號(hào)字符標(biāo)記為1,這樣可以在之后的替換模式表達(dá)式中引用它
([^,]*), 我們必須找到0或者多個(gè)非逗號(hào)字符后面跟著一個(gè)逗號(hào),并且非逗號(hào)字符那部分要標(biāo)記出來以備后用。

現(xiàn)在正是指出一個(gè)使用正則表達(dá)式常見錯(cuò)誤的最佳時(shí)機(jī)。為什么我們要使用[^,]*這樣的一個(gè)表達(dá)式,而不是更加簡(jiǎn)單直接的寫法,例如:.*,來匹配第一個(gè)參數(shù)呢?設(shè)想我們使用模式.*來匹配字符串"10,7,2",它應(yīng)該匹配"10,"還是"10,7,"?為了解決這個(gè)兩義性(ambiguity),正則表達(dá)式規(guī)定一律按照最長(zhǎng)的串來,在上面的例子中就是"10,7,",顯然這樣就找出了兩個(gè)參數(shù)而不是我們期望的一個(gè)。所以,我們要使用[^,]*來強(qiáng)制取出第一個(gè)逗號(hào)之前的部分。

這個(gè)表達(dá)式我們已經(jīng)分析到了:foo(([^,]*),這一段可以簡(jiǎn)單的翻譯為“當(dāng)你找到foo(就把其后直到第一個(gè)逗號(hào)之前的部分標(biāo)記為1”。然后我們使用同樣的辦法標(biāo)記第二個(gè)參數(shù)為2。對(duì)第三個(gè)參數(shù)的標(biāo)記方法也是一樣,只是我們要搜索所有的字符直到右括號(hào)。我們并沒有必要去搜索第三個(gè)參數(shù),因?yàn)槲覀儾恍枰{(diào)整它的位置,但是這樣的模式能夠保證我們只去替換那些有三個(gè)參數(shù)的foo()方法調(diào)用,在foo()是一個(gè)重載(overoading)方法時(shí)這種明確的模式往往是比較保險(xiǎn)的。然后,在替換部分,我們找到foo()的對(duì)應(yīng)實(shí)例,然后利用標(biāo)記好的部分進(jìn)行替換,是的第一和第二個(gè)參數(shù)交換位置。

例2

假設(shè)有一個(gè)CSV(comma separated value)文件,里面有一些我們需要的信息,但是格式卻有問題,目前數(shù)據(jù)的列順序是:姓名,公司名,州名縮寫,郵政編碼,現(xiàn)在我們希望講這些數(shù)據(jù)重新組織,以便在我們的某個(gè)軟件中使用,需要的格式為:姓名,州名縮寫-郵政編碼,公司名。也就是說,我們要調(diào)整列順序,還要合并兩個(gè)列來構(gòu)成一個(gè)新列。另外,我們的軟件不能接受逗號(hào)前后面有任何空格(包括空格和制表符)所以我們還必須要去掉逗號(hào)前后的所有空格。

這里有幾行我們現(xiàn)在的數(shù)據(jù):

    Bill Jones,     HI-TEK Corporation ,  CA, 95011
    Sharon Lee Smith,  Design Works Incorporated,  CA, 95012
    B. Amos   ,  Hill Street Cafe,  CA, 95013
    Alexander Weatherworth,  The Crafts Store,  CA, 95014
    ...
我們希望把它變成這個(gè)樣子:
    Bill Jones,CA 95011,HI-TEK Corporation
    Sharon Lee Smith,CA 95012,Design Works Incorporated
    B. Amos,CA 95013,Hill Street Cafe
    Alexander Weatherworth,CA 95014,The Crafts Store
    ...
我們將用兩個(gè)正則表達(dá)式來解決這個(gè)問題。第一個(gè)移動(dòng)列和合并列,第二個(gè)用來去掉空格。

下面就是第一個(gè)替換命令:

    :%s/([^,]*),([^,]*),([^,]*),(.*)/1,3 4,2/
這里的方法跟例1基本一樣,第一個(gè)列(姓名)用這個(gè)表達(dá)式來匹配:([^,]*),即第一個(gè)逗號(hào)之前的所有字符,而姓名內(nèi)容被用1標(biāo)記下來。公司名和州名縮寫字段用同樣的方法標(biāo)記為23,而最后一個(gè)字段用(.*)來匹配("匹配所有字符直到行末")。替換部分則引用上面標(biāo)記的那些內(nèi)容來進(jìn)行構(gòu)造。

下面這個(gè)替換命令則用來去除空格:

    :%s/[ t]*,[ t]*/,/g
我們還是分解來看:[ t]匹配空格/制表符,[ t]* 匹配0或多個(gè)空格/制表符,[ t]*,匹配0或多個(gè)空格/制表符后面再加一個(gè)逗號(hào),最后,[ t]*,[ t]*匹配0或多個(gè)空格/制表符接著一個(gè)逗號(hào)再接著0或多個(gè)空格/制表符。在替換部分,我們簡(jiǎn)單的我們找到的所有東西替換成一個(gè)逗號(hào)。這里我們使用了結(jié)尾的可選的g參數(shù),這表示在每行中對(duì)所有匹配的串執(zhí)行替換(而不是缺省的只替換第一個(gè)匹配串)。

例3

假設(shè)有一個(gè)多字符的片斷重復(fù)出現(xiàn),例如:
Billy tried really hard
Sally tried really really hard
Timmy tried really really really hard
Johnny tried really really really really hard
而你想把"really"、"really really",以及任意數(shù)量連續(xù)出現(xiàn)的"really"字符串換成一個(gè)簡(jiǎn)單的"very"(simple is good!),那么以下命令:
:%s/(really )(really )*/very /
就會(huì)把上述的文本變成:
Billy tried very hard
Sally tried very hard
Timmy tried very hard
Johnny tried very hard
表達(dá)式(really )*匹配0或多個(gè)連續(xù)的"really "(注意結(jié)尾有個(gè)空格),而(really )(really )* 匹配1個(gè)或多個(gè)連續(xù)的"really "實(shí)例。

困難的例子(不可思議的象形文字)

Coming soon.

 


不同工具中的正則表達(dá)式

OK,你已經(jīng)準(zhǔn)備使用RE(regular expressions,正則表達(dá)式),但是你并準(zhǔn)備使用vi。所以,在這里我們給出一些在其他工具中使用RE的例子。另外,我還會(huì)總結(jié)一下你在不同程序之間使用RE可能發(fā)現(xiàn)的區(qū)別。

當(dāng)然,你也可以在Visual C++編輯器中使用RE。選擇Edit->Replace,然后選擇"Regular expression"選擇框,F(xiàn)ind What輸入框?qū)?yīng)上面介紹的vi命令:%s/pat1/pat2/g中的pat1部分,而Replace輸入框?qū)?yīng)pat2部分。但是,為了得到vi的執(zhí)行范圍和g選項(xiàng),你要使用Replace All或者適當(dāng)?shù)氖止ind Next and Replace(譯者按:知道為啥有人罵微軟弱智了吧,雖然VC中可以選中一個(gè)范圍的文本,然后在其中執(zhí)行替換,但是總之不夠vi那么靈活和典雅)。

sed

Sed是Stream EDitor的縮寫,是Unix下常用的基于文件和管道的編輯工具,可以在手冊(cè)中得到關(guān)于sed的詳細(xì)信息。

這里是一些有趣的sed腳本,假定我們正在處理一個(gè)叫做price.txt的文件。注意這些編輯并不會(huì)改變?cè)次募?,sed只是處理源文件的每一行并把結(jié)果顯示在標(biāo)準(zhǔn)輸出中(當(dāng)然很容易使用重定向來定制):

sed腳本   描述


sed 's/^$/d' price.txt 刪除所有空行
sed 's/^[ t]*$/d' price.txt 刪除所有只包含空格或者制表符的行
sed 's/"http://g' price.txt 刪除所有引號(hào)

awk

awk是一種編程語言,可以用來對(duì)文本數(shù)據(jù)進(jìn)行復(fù)雜的分析和處理??梢栽谑謨?cè)中得到關(guān)于awk的詳細(xì)信息。這個(gè)古怪的名字是它作者們的姓的縮寫(Aho,Weinberger和Kernighan)。

在Aho,Weinberger和Kernighan的書The AWK Programming Language中有很多很好的awk的例子,請(qǐng)不要讓下面這些微不足道的腳本例子限制你對(duì)awk強(qiáng)大能力的理解。我們同樣假定我們針對(duì)price.txt文件進(jìn)行處理,跟sed一樣,awk也只是把結(jié)果顯示在終端上。 

awk腳本   描述


awk '$0 !~ /^$/' price.txt 刪除所有空行
awk 'NF > 0' price.txt awk中一個(gè)更好的刪除所有行的辦法
awk '$2 ~ /^[JT]/ {print $3}' price.txt 打印所有第二個(gè)字段是'J'或者'T'打頭的行中的第三個(gè)字段
awk '$2 !~ /[Mm]isc/ {print $3 + $4}' price.txt 針對(duì)所有第二個(gè)字段不包含'Misc'或者'misc'的行,打印第3和第4列的和(假定為數(shù)字)
awk '$3 !~ /^[0-9]+.[0-9]*$/ {print $0}' price.txt 打印所有第三個(gè)字段不是數(shù)字的行,這里數(shù)字是指d.d或者d這樣的形式,其中d是0到9的任何數(shù)字
awk '$2 ~ /John|Fred/ {print $0}' price.txt 如果第二個(gè)字段包含'John'或者'Fred'則打印整行

grep

grep是一個(gè)用來在一個(gè)或者多個(gè)文件或者輸入流中使用RE進(jìn)行查找的程序。它的name編程語言可以用來針對(duì)文件和管道進(jìn)行處理??梢栽谑謨?cè)中得到關(guān)于grep的完整信息。這個(gè)同樣古怪的名字來源于vi的一個(gè)命令,g/re/p,意思是global regular expression print。

下面的例子中我們假定在文件phone.txt中包含以下的文本,——其格式是姓加一個(gè)逗號(hào),然后是名,然后是一個(gè)制表符,然后是電話號(hào)碼:

    Francis, John           5-3871
    Wong, Fred              4-4123
    Jones, Thomas           1-4122
    Salazar, Richard        5-2522

grep命令   描述


grep 't5-...1' phone.txt 把所有電話號(hào)碼以5開頭以1結(jié)束的行打印出來,注意制表符是用t表示的
grep '^S[^ ]* R' phone.txt 打印所有姓以S打頭和名以R打頭的行
grep '^[JW]' phone.txt 打印所有姓開頭是J或者W的行
grep ', ....t' phone.txt 打印所有姓是4個(gè)字符的行,注意制表符是用t表示的
grep -v '^[JW]' phone.txt 打印所有不以J或者W開頭的行
grep '^[M-Z]' phone.txt 打印所有姓的開頭是M到Z之間任一字符的行
grep '^[M-Z].*[12]' phone.txt 打印所有姓的開頭是M到Z之間任一字符,并且點(diǎn)號(hào)號(hào)碼結(jié)尾是1或者2的行

egrep

egrep是grep的一個(gè)擴(kuò)展版本,它在它的正則表達(dá)式中支持更多的元字符。下面的例子中我們假定在文件phone.txt中包含以下的文本,——其格式是姓加一個(gè)逗號(hào),然后是名,然后是一個(gè)制表符,然后是電話號(hào)碼:
    Francis, John           5-3871
    Wong, Fred              4-4123
    Jones, Thomas           1-4122
    Salazar, Richard        5-2522

egrep command   Description


egrep '(John|Fred)' phone.txt 打印所有包含名字John或者Fred的行
egrep 'John|22$|^W' phone.txt 打印所有包含John 或者以22結(jié)束或者以W的行
egrep 'net(work)?s' report.txt 從report.txt中找到所有包含networks或者nets的行


正則表達(dá)式語法支持情況

命令或環(huán)境 . [ ] ^ $ ( ) { } ? + | ( )
vi  X   X   X   X   X           
Visual C++  X   X   X   X   X           
awk  X   X   X   X       X   X   X   X 
sed  X   X   X   X   X   X         
Tcl  X   X   X   X   X     X   X   X   X 
ex  X   X   X   X   X   X         
grep  X   X   X   X   X   X         
egrep  X   X  X   X   X     X   X   X   X 
fgrep  X   X   X   X   X           
perl  X  X  X  X  X    X  X  X  X

 


vi替換命令簡(jiǎn)介

Vi的替換命令:
    :ranges/pat1/pat2/g
其中
    : 這是Vi的命令執(zhí)行界面。
    range 是命令執(zhí)行范圍的指定,可以使用百分號(hào)(%)表示所有行,使用點(diǎn)(.)表示當(dāng)前行,使用美元符號(hào)($)表示最后一行。你還可以使用行號(hào),例如10,20表示第10到20行,.,$表示當(dāng)前行到最后一行,.+2,$-5表示當(dāng)前行后兩行直到全文的倒數(shù)第五行,等等。

    s 表示其后是一個(gè)替換命令。

    pat1 這是要查找的一個(gè)正則表達(dá)式,這篇文章中有一大堆例子。

    pat2 這是希望把匹配串變成的模式的正則表達(dá)式,這篇文章中有一大堆例子。

    g 可選標(biāo)志,帶這個(gè)標(biāo)志表示替換將針對(duì)行中每個(gè)匹配的串進(jìn)行,否則則只替換行中第一個(gè)匹配串。

網(wǎng)上有很多vi的在線手冊(cè),你可以訪問他們以獲得更加完整的信息。

snoics 2005-10-09 14:04 發(fā)表評(píng)論
]]>
主站蜘蛛池模板: 上高县| 藁城市| 永和县| 石首市| 永靖县| 略阳县| 富民县| 杭锦后旗| 盐津县| 永吉县| 天津市| 新晃| 天气| 唐海县| 镇巴县| 遂昌县| 岱山县| 枝江市| 章丘市| 泰宁县| 平潭县| 上蔡县| 远安县| 乌海市| 延庆县| 福建省| 静海县| 井冈山市| 永靖县| 克东县| 手游| 巴楚县| 黑水县| 连云港市| 邯郸县| 通化县| 新干县| 新化县| 富源县| 普安县| 玛多县|