亚洲国产精品第一区二区,婷婷亚洲综合一区二区,亚洲Av永久无码精品一区二区http://www.tkk7.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> 天很高,云很淡 風很輕,海很藍<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中文處理學習筆記——Hello Unicode [轉]http://www.tkk7.com/snoics/articles/16575.htmlsnoicssnoicsMon, 24 Oct 2005 06:27:00 GMThttp://www.tkk7.com/snoics/articles/16575.htmlhttp://www.tkk7.com/snoics/comments/16575.htmlhttp://www.tkk7.com/snoics/articles/16575.html#Feedback0http://www.tkk7.com/snoics/comments/commentRss/16575.htmlhttp://www.tkk7.com/snoics/services/trackbacks/16575.html閱讀全文

snoics 2005-10-24 14:27 發表評論
]]>
Unicode 問答集 [轉]http://www.tkk7.com/snoics/articles/16574.htmlsnoicssnoicsMon, 24 Oct 2005 06:24:00 GMThttp://www.tkk7.com/snoics/articles/16574.htmlhttp://www.tkk7.com/snoics/comments/16574.htmlhttp://www.tkk7.com/snoics/articles/16574.html#Feedback0http://www.tkk7.com/snoics/comments/commentRss/16574.htmlhttp://www.tkk7.com/snoics/services/trackbacks/16574.html圖標

Unicode 問答集

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

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

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

問:Unicode的優點是什么?
答:舉一個最明顯的例子就是Windows 2000/XP以及微軟Office2000及其后的產品。因為這些軟件都是Unicode內核,因此,無論何種文字,都可以在上面正常顯示,而且是同屏顯示。以前,簡體中文的Word文件拿到英文版打開就會是亂碼,簡體中文的程序在Windows英文版上運行會出現亂碼,而現在一切都解決了。

問:中國京劇戲考為什么使用Unicode?
答:因為有些劇本中的生僻字,只在擴展字庫或繁體字庫中才有,有的甚至沒有。而Unicode不僅包含了所有常用字和大部分生僻字,而且因為其可擴展,在現在沒有的情況下,將來也是可以擴充的。例如最新的Unicode 4.0標準,較3.0增加了很多生僻字。目前有70207個漢字。再有一點就是Unicode在將來會取代現有的GBK及BIG5。

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



snoics 2005-10-24 14:24 發表評論
]]>
關于Unicode [轉]http://www.tkk7.com/snoics/articles/16572.htmlsnoicssnoicsMon, 24 Oct 2005 06:21:00 GMThttp://www.tkk7.com/snoics/articles/16572.htmlhttp://www.tkk7.com/snoics/comments/16572.htmlhttp://www.tkk7.com/snoics/articles/16572.html#Feedback0http://www.tkk7.com/snoics/comments/commentRss/16572.htmlhttp://www.tkk7.com/snoics/services/trackbacks/16572.html關于Unicode

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

在互聯網上關于Unicode的信息。

Unicode協會提供了大量的文檔,包括

標準

標準當前的版本是3.0.1。

Qt中的Unicode

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

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

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

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

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

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

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

tr()(有時被簡化)從const char *映射到Unicode字符串,并且使用QTranslator對象來進行這個映射。

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

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

盡管US-ASCII和ISO-8859-1是非常普通的,這里也提供了可以和它們互相映射的特別快的函數。舉例來說,打開一個應用程序的圖標也許會這樣做:

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

關于輸出,Qt對于從Unicode到任何一個系統和字體提供的編碼的轉換作出了最大的努力?;诓僮飨到y、本地和字體的可用性和Qt對所使用的字符的支持,這種轉換也許是好的,也許是壞的。我們將在即將推出的版本中繼續改進,以最普通的地區編碼作為重點。


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


snoics 2005-10-24 14:21 發表評論
]]>
UTF-8 and Unicode FAQ [轉]http://www.tkk7.com/snoics/articles/16571.htmlsnoicssnoicsMon, 24 Oct 2005 06:19:00 GMThttp://www.tkk7.com/snoics/articles/16571.htmlhttp://www.tkk7.com/snoics/comments/16571.htmlhttp://www.tkk7.com/snoics/articles/16571.html#Feedback0http://www.tkk7.com/snoics/comments/commentRss/16571.htmlhttp://www.tkk7.com/snoics/services/trackbacks/16571.htmlUTF-8 and Unicode FAQ

by Markus Kuhn

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

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

UTF-8 編碼提供了一種簡便而向后兼容的方法, 使得那種完全圍繞 ASCII 設計的操作系統, 比如 Unix, 也可以使用 Unicode. UTF-8 就是 Unix, Linux 已經類似的系統使用 Unicode 的方式. 現在是你了解它的時候了.

什么是 UCS 和 ISO 10646?

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

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

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

UCS 不僅給每個字符分配一個代碼, 而且賦予了一個正式的名字. 表示一個 UCS 或 Unicode 值的十六進制數, 通常在前面加上 "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, 已經 BMP 以外的大范圍的編碼是為私用保留的.

什么是組合字符?

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

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

什么是 UCS 實現級別?

不是所有的系統都需要支持象組合字符這樣的 UCS 里所有的先進機制. 因此 ISO 10646 指定了下列三種實現級別:

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

什么是 Unicode?

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

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

Unicode 協會公布的 Unicode 標準 嚴密地包含了 ISO 10646-1 實現級別3的基本多語言面. 在兩個標準里所有的字符都在相同的位置并且有相同的名字.

Unicode 標準額外定義了許多與字符有關的語義符號學, 一般而言是對于實現高質量的印刷出版系統的更好的參考. Unicode 詳細說明了繪制某些語言(比如阿拉伯語)表達形式的算法, 處理雙向文字(比如拉丁與希伯來文混合文字)的算法和 排序與字符串比較 所需的算法, 以及其他許多東西.

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

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

什么是 UTF-8?

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

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

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

UTF-8 有一下特性:

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

下列字節串用來表示一個字符. 用到哪個串取決于該字符在 Unicode 中的序號.

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 的位置由字符編碼數的二進制表示的位填入. 越靠右的 x 具有越少的特殊意義. 只用最短的那個足夠表達一個字符編碼數的多字節串. 注意在多字節串中, 第一個字節的開頭"1"的數目就是整個串中字節的數目.

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

11000010 10101001 = 0xC2 0xA9

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

11100010 10001001 10100000 = 0xE2 0x89 0xA0

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

什么編程語言支持 Unicode?

在大約 1993 年之后開發的大多數現代編程語言都有一個特別的數據類型, 叫做 Unicode/ISO 10646-1 字符. 在 Ada95 中叫 Wide_Character, 在 Java 中叫 char.

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

在 Linux 下該如何使用 Unicode?

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

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

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

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

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

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

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

我該怎樣修改我的軟件?

有兩種途徑可以支持 UTF-8, 我稱之為軟轉換與硬轉換. 軟轉換時, 各處的數據均保存為 UTF-8 形式, 因而需要修改的軟件很少. 在硬轉換時, 程序將讀入的 UTF-8 數據轉換成寬字符數組, 以在應用程序內部處理. 在輸出時, 再把字符串轉換回 UTF-8 形式.

大多數應用程序只用軟轉換就可以工作得很好了. 這使得將 UTF-8 引入 Unix 成為切實可行的. 例如, 象 cat 和 echo 這樣的程序根本不需要修改. 他們仍然可以對輸入輸出的是 ISO 8859-2 還是 UTF-8 一無所知, 因為它們只是搬運字節流而沒有處理它們. 它們只能識別 ASCII 字符和象 '\n' 這樣的控制碼, 而這在 UTF-8 下也沒有任何改變. 因此, 這些應用程序的 UTF-8 編碼與解碼將完全在終端模擬器里完成.

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

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

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

C 對 Unicode 和 UTF-8 的支持

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

例如, 你可以寫

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

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

注意, 類似這樣的操作:

  char c = L"a"; 

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

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

怎樣激活 UTF-8 模式?

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

當前的應用程序使用許許多多的不同的命令行開關來激活它們各自的 UTF-8 模式, 例如:

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

記住每一個應用程序的命令行選項或其他配置方法是非常單調乏味的, 因此急需某種標準方法.

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

然而, 大多數現存軟件的維護者選擇用軟轉換來代替, 而不使用 libc 的寬字符函數, 不僅因為它們還未得到廣泛應用, 還因為這會使得軟件進行大規模修改. 在這種情況下, 你的應用程序必須自己來獲知何時使用 UTF-8 模式. 一種方式是做以下工作:

按照環境變量 LC_ALL, LC_CTYPE, LANG 的順序, 尋找第一個有值的變量. 如果該值包含 UTF-8 子串 (也許是小寫或沒有"-") 則默認為 UTF-8 模式 (仍然可以用命令行開關來重設), 因為這個值可靠又恰當地指示了 C 庫應該使用一種 UTF-8 locale.

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

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

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

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

xterm 支持組合字符嗎?

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

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

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

  /* 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 庫也提供了函數

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

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

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

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

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

在過去的幾個月里出現了相當多的 X11 的 Unicode 字體, 并且還在快速增多.

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

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

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

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

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

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

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

與 UTF-8 終端模擬器相關的問題是什么?

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

UTF-8 在 ISO 2022 的意義里是一個 "其他編碼系統" (參考 ECMA 35 的 15.4 節). UTF-8 是在 ISO 2022 SS2/SS3/G0/G1/G2/G3 世界之外的, 因此如果你從 ISO 2022 切換到 UTF-8, 所有的 SS2/SS3/G0/G1/G2/G3 狀態都變得沒有意義了, 直到你離開 UTF-8 并切換回 ISO 2022. UTF-8 是一個沒有國家的編碼, 也就是一個自我終結的短字節序列完全決定了它代表什么字符, 獨立于任何國家的切換. G0 與 G1 在 ISO 10646 里與在 ISO 8859-1 里相同, 而 G2/G3 在 ISO 10646 里不存在, 因為任何字符都有固定的位置, 因而不會發聲切換. 在 UTF-8 模式下, 你的終端不會因為你偶然地裝入一個二進制文件而切換入一種奇怪圖形字符模式. 這使得一個終端在 UTF-8 模式下比在 ISO 2022 模式下要健壯得多, 而且因此可以有辦法將終端鎖在 UTF-8 模式里, 而不會偶然地回到 ISO 2022 世界里.

ISO 2022 標準指定了一系列的 ESC % 序列, 以離開 ISO 2022 世界 (指定其他的編碼系統, DOCS), 用于 UTF-8 的許多這樣的序列已經注冊進了 ISO 2375 International Register of Coded Character Sets:

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

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

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

已經有哪些支持 UTF-8 的應用程序了?

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

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

Postscript 字形的名字與 UCS 代碼是怎么關聯的?

參考 Adobe 的 Unicode and Glyph Names 指南.

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

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

現在有沒有用于處理 Unicode 的免費的庫?

各種 X widget 對 Unicode 支持的現狀如何?

有什么關于這個話題的好的郵件列表?

你確實應該訂閱的是 unicode@unicode.org 郵件列表, 這是發現標準的作者和其他許多領袖的話語的最好辦法. 訂閱方法是, 用 "subscribe" 作為標題, "subscribe YOUR@EMAIL.ADDRESS unicode" 作為正文, 發一條消息到 unicode-request@unicode.org.

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

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

更多參考

我不斷地將新的材料加入這份文檔, 因此請定期來查看. 歡迎所有關于改進的建議, 以及自由軟件社區里關于改善 UTF-8 支持的廣告. UTF-8 用在 Linux 里是新近的事, 因此我們在將來的幾個月里可以見到大量的進展.

特別感謝 Ulrich Drepper 和 Bruno Haible 的有價值的注解

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



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

---- 策略文件可以儲存在無格式的ASCII文件或Policy類的二進制文件或數據庫中。本文僅討論無格式的ASCII文件的形式。

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

----一個Policy文件實質上是一個記錄列表,它可能含有一個 “keystore”記錄,以及含有零個或多個“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"記錄

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

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

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

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

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

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

----target_name用來指定目標類的位置,action用于指定目標類擁有的權限。

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

directory/* 目錄下的所有文件
* 當前目錄的所有文件
directory/- 目錄下的所有文件,包括子目錄
- 當前目錄下的所有文件,包括子目錄
<< ALL FILES >>文件系統中的所有文件

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

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

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

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

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

三、實 例
----當初始化Policy時,首先裝載系統Policy,然后再增加用戶Policy,如果兩者都不存在,則使用缺省的Policy,即原始的沙箱模型。
----系統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)

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

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

// For LanServerTalk.java and LanClientTalk.java

grant {
//對系統和用戶目錄“讀”的權限
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";

//對線程和線程組的操作權限
permission java.lang.RuntimePermission “modifyThread";
permission java.lang.RuntimePermission “modifyThreadGroup";

//操作Socket端口的各種權限
permission java.net.SocketPermission “-", “listen";
permission java.net.SocketPermission “-", “accept";
permission java.net.SocketPermission “-", “connect";
permission java.net.SocketPermission “-", “read";
permission java.net.SocketPermission “-", “write";

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

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

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

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

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

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

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

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

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

----這種方法使用靈活,特別是作為一個軟件包在企業內部網中發布時,安裝、設置和遷移軟件,基本無須修改Policy文件的內容,使用起來相當簡單,而且,安全許可的范圍控制較精細。

摘自《計算機世界》


snoics 2005-10-14 17:48 發表評論
]]>
JAVA面試題集 [轉]http://www.tkk7.com/snoics/articles/15489.htmlsnoicssnoicsFri, 14 Oct 2005 02:15:00 GMThttp://www.tkk7.com/snoics/articles/15489.htmlhttp://www.tkk7.com/snoics/comments/15489.htmlhttp://www.tkk7.com/snoics/articles/15489.html#Feedback0http://www.tkk7.com/snoics/comments/commentRss/15489.htmlhttp://www.tkk7.com/snoics/services/trackbacks/15489.html閱讀全文

snoics 2005-10-14 10:15 發表評論
]]>
正則表達式簡介 [轉]http://www.tkk7.com/snoics/articles/15059.htmlsnoicssnoicsSun, 09 Oct 2005 07:01:00 GMThttp://www.tkk7.com/snoics/articles/15059.htmlhttp://www.tkk7.com/snoics/comments/15059.htmlhttp://www.tkk7.com/snoics/articles/15059.html#Feedback0http://www.tkk7.com/snoics/comments/commentRss/15059.htmlhttp://www.tkk7.com/snoics/services/trackbacks/15059.html【javascript】在javascript中使用正則表達式- -

這些頁包含的信息其目的是提供一個關于正則表達式的通用介紹。

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

“正則表達式簡介”包括下述各個主題:

正則表達式

早期起源

使用正則表達式

正則表達式語法

建立正則表達式

優先權順序

普通字符

特殊字符

非打印字符

字符匹配

限定符

定位符

選擇與編組

后向引用

正則表達式

如果原來沒有使用過正則表達式,那么可能對這個術語和概念會不太熟悉。不過,它們并不是您想象的那么新奇。

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

data1.dat

data2.dat

datax.dat

dataN.dat

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

data.dat

data1.dat

data2.dat

data12.dat

datax.dat

dataXYZ.dat

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

早期起源

正則表達式的“祖先”可以一直上溯至對人類神經系統如何工作的早期研究。Warren McCulloch 和 Walter Pitts 這兩位神經生理學家研究出一種數學方式來描述這些神經網絡。

1956 年, 一位叫 Stephen Kleene 的美國數學家在 McCulloch 和 Pitts 早期工作的基礎上,發表了一篇標題為“神經網事件的表示法”的論文,引入了正則表達式的概念。正則表達式就是用來描述他稱為“正則集的代數”的表達式,因此采用“正則表達式”這個術語。

隨后,發現可以將這一工作應用于使用Ken Thompson 的計算搜索算法的一些早期研究,Ken Thompson是Unix 的主要發明人。正則表達式的第一個實用應用程序就是 Unix 中的qed 編輯器。

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

使用正則表達式

在典型的搜索和替換操作中,必須提供要查找的確切文字。這種技術對于靜態文本中的簡單搜索和替換任務可能足夠了,但是由于它缺乏靈活性,因此在搜索動態文本時就有困難了,甚至是不可能的。

使用正則表達式,就可以:

  • 測試字符串的某個模式。例如,可以對一個輸入字符串進行測試,看在該字符串是否存在一個電話號碼模式或一個信用卡號碼模式。這稱為數據有效性驗證。
  • 替換文本??梢栽谖臋n中使用一個正則表達式來標識特定文字,然后可以全部將其刪除,或者替換為別的文字。
  • 根據模式匹配從字符串中提取一個子字符串??梢杂脕碓谖谋净蜉斎胱侄沃胁檎姨囟ㄎ淖?。

例如,如果需要搜索整個 web 站點來刪除某些過時的材料并替換某些HTML 格式化標記,則可以使用正則表達式對每個文件進行測試,看在該文件中是否存在所要查找的材料或 HTML 格式化標記。用這個方法,就可以將受影響的文件范圍縮小到包含要刪除或更改的材料的那些文件。然后可以使用正則表達式來刪除過時的材料,最后,可以再次使用正則表達式來查找并替換那些需要替換的標記。

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

正則表達式語法

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

這里有一些可能會遇到的正則表達式示例:

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

 

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

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

建立正則表達式

構造正則表達式的方法和創建數學表達式的方法一樣。也就是用多種元字符與操作符將小的表達式結合在一起來創建更大的表達式。

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

/expression/

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

"expression"

在上面所示的兩個示例中,正則表達式模式 (expression) 均存儲在RegExp 對象的Pattern 屬性中。

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

優先權順序

在構造正則表達式之后,就可以象數學表達式一樣來求值,也就是說,可以從左至右并按照一個優先權順序來求值。

下表從最高優先級到最低優先級列出各種正則表達式操作符的優先權順序:

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

普通字符

普通字符由所有那些未顯式指定為元字符的打印和非打印字符組成。這包括所有的大寫和小寫字母字符,所有數字,所有標點符號以及一些符號。

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

/a/
/7/
/M/

等價的 VBScript 單字符正則表達式為:

"a"
"7"
"M"

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

/a7M/

等價的 VBScript 表達式為:

"a7M"

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

特殊字符

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

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

非打印字符

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

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

字符匹配

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

/a.c/

等價的 VBScript 正則表達式為:

"a.c"

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

/filename\.ext/

對 VBScript 而言,等價的表達式如下所示:

"filename\.ext"

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

括號表達式

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

  • ']' 字符如果不是第一項,則將結束一個列表。要在列表中匹配 ']' 字符,請將其放在第一項,緊跟在開始的 '[' 后面。
  • '\' 仍然作為轉義符。要匹配 '\' 字符,請使用 '\\'。

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

/Chapter [12345]/

在 VBScript 中要匹配同樣的章節標題,請使用下面的表達式:

"Chapter [12345]"

請注意單詞 'Chapter' 及后面的空格與括號內的字符的位置關系是固定的。因此,括號表達式只用來指定滿足緊跟在單詞 'Chapter' 和一個空格之后的單字符位置的字符集合。這里是第九個字符位置。

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

/Chapter [1-5]/

VBScipt 中相同功能的表達式如下所示:

"Chapter [1-5]"

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

如果想在括號表達式中包括連字符,則必須使用下述方法之一:

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

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

/Chapter [^12345]/

對 VBScript 則使用:

"Chapter [^12345]"

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

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

/Chapter [^1-5]/

或者,對 VBScript 為:

"Chapter [^1-5]"

括號表達式的典型用法是指定對任何大寫或小寫字母字符或任何數字的匹配。下面的 JScript 表達式給出了這一匹配:

/[A-Za-z0-9]/

等價的 VBScript 表達式為:

"[A-Za-z0-9]"

限定符

有時候不知道要匹配多少字符。為了能適應這種不確定性,正則表達式支持限定符的概念。這些限定符可以指定正則表達式的一個給定組件必須要出現多少次才能滿足匹配。

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

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

 

對一個很大的輸入文檔而言,章節數很輕易就超過九章,因此需要有一種方法來處理兩位數或者三位數的章節號。限定符就提供了這個功能。下面的JScript 正則表達式可以匹配具有任何位數的章節標題:

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

下面的 VBScript 正則表達式執行同樣的匹配:

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

請注意限定符出現在范圍表達式之后。因此,它將應用于所包含的整個范圍表達式,在本例中,只指定了從 0 到 9 的數字。

這里沒有使用 '+' 限定符,因為第二位或后續位置上并不一定需要一個數字。同樣也沒有使用 '?' 字符,因為這將把章節數限制為只有兩位數字。在 'Chapter' 和空格字符之后至少要匹配一個數字。

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

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

對 VBScript 可以使用下述正則表達式:

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

上述表達式的缺點是如果有一個章節號大于 99,它仍只會匹配前兩位數字。另一個缺點是某些人可以創建一個 Chapter 0,而且仍能匹配。一個更好的用來匹配兩位數的 JScript 表達式如下:

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

或者

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

對 VBScript 而言,下述表達式與上面等價:

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

或者

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

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

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

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

下面的表達式匹配從開始的小于號 (<) 到 H1 標記結束處的大于號之間的所有內容。

/<.*>/

 VBScript 的正則表達式為:

"<.*>"

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

/<.*?>/

或者

"<.*?>"

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

定位符

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

定位符提供了這個功能。定位符可以將一個正則表達式固定在一行的開始或結束。也可以創建只在單詞內或只在單詞的開始或結尾處出現的正則表達式。下表包含了正則表達式及其含義的列表:

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

 

不能對定位符使用限定符。因為在一個換行符或者單詞邊界的前面或后面不會有連續多個位置,因此諸如 '^*' 的表達式是不允許的。

要匹配一行文字開始位置的文字,請在正則表達式的開始處使用 '^' 字符。不要把 '^' 的這個語法與其在括號表達式中的語法弄混。它們的語法根本不同。

要匹配一行文字結束位置的文字,請在正則表達式的結束處使用 '$' 字符。

要在查找章節標題時使用定位符,下面的 JScript 正則表達式將匹配位于一行的開始處最多有兩個數字的章節標題:

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

VBScript 中相同功能的正則表達式如下:

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

一個真正的章節標題不僅出現在一行的開始,而且這一行中也僅有這一個內容,因此,它必然也位于一行的結束。下面的表達式確保所指定的匹配只匹配章節而不會匹配交叉引用。它是通過創建一個只匹配一行文字的開始和結束位置的正則表達式來實現的。

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

對 VBScript 則使用:

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

匹配單詞邊界有少許不同,但卻給正則表達式增加了一個非常重要的功能。單詞邊界就是單詞和空格之間的位置。非單詞邊界就是其他任何位置。下面的 JScript 表達式將匹配單詞 'Chapter' 的前三個字符,因為它們出現在單詞邊界后:

/\bCha/

對 VBScript 為:

"\bCha"

這里 '\b' 操作符的位置很關鍵。如果它位于要匹配的字符串的開始,則將查找位于單詞開頭處的匹配;如果它位于改字符串的末尾,則查找位于單詞結束處的匹配。例如,下面的表達式將匹配單詞 'Chapter' 中的 'ter',因為它出現在單詞邊界之前:

/ter\b/

以及

"ter\b"

下面的表達式將匹配 'apt',因為它位于 'Chapter' 中間,但不會匹配 'aptitude' 中的'apt':

/\Bapt/

以及

"\Bapt"

這是因為在單詞 'Chapter' 中 'apt' 出現在非單詞邊界位置,而在單詞 'aptitude' 中位于單詞邊界位置。非單詞邊界操作符的位置不重要,因為匹配與一個單詞的開頭或結尾無關。

選擇與編組

選擇允許使用 '|' 字符來在兩個或多個候選項中進行選擇。通過擴展章節標題的正則表達式,可以將其擴充為不僅僅適用于章節標題的表達式。不過,這可沒有想象的那么直接。在使用選擇時,將匹配'|' 字符每邊最可能的表達式。你可能認為下面的 JScript 和 VBScript 表達式將匹配位于一行的開始和結束位置且后跟一個或兩個數字的 'Chapter' 或 'Section':

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

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

可以使用圓括號來限制選擇的范圍,也就是說明確該選擇只適用于這兩個單詞 'Chapter' 和 'Section'。不過,圓括號同樣也是難處理的,因為它們也用來創建子表達式,有些內容將在后面關于子表達式的部分介紹。通過采用上面所示的正則表達式并在適當位置添加圓括號,就可以使該正則表達式既可以匹配 'Chapter 1',也可以匹配 'Section 3'。

下面的正則表達式使用圓括號將 'Chapter' 和 'Section' 組成一組,所以該表達式才能正確工作。對 JScript 為:

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

對 VBScript 為:

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

這些表達式工作正確,只是產生了一個有趣的副產品。在 'Chapter|Section' 兩邊放置圓括號建立了適當的編組,但也導致兩個待匹配單詞之一都被捕獲供今后使用。由于在上面所示的表達式中只有一組圓括號,因此只能有一個捕獲的 submatch。可以使用 VBScript 的Submatches 集合或者JScript 中RegExp 對象的 $1-$9 屬性來引用這個子匹配。

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

可以在正則表達式模式圓括號內部的前面使用 '?:'來防止存儲該匹配供今后使用。對上面所示正則表達式的下述修改提供了免除子匹配存儲的相同功能。對 JScript:

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

對 VBScript:

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

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

例如,假定有一個包含引用有 Windows 3.1、Windows 95、Windows 98 以及 Windows NT 的文檔。進一步假設需要更新該文檔,方法是查找所有對 Windows 95、Windows 98 以及 Windows NT 的引用,并將這些引用更改為 Windows 2000。可以使用下面的 JScript 正則表達式,這是一個正向預查,來匹配 Windows 95、Windows 98 以及 Windows NT:

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

在 VBScript 要進行同樣的匹配可以使用下述表達式:

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

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

后向引用

正則表達式一個最重要的特性就是將匹配成功的模式的某部分進行存儲供以后使用這一能力。請回想一下,對一個正則表達式模式或部分模式兩邊添加圓括號將導致這部分表達式存儲到一個臨時緩沖區中。可以使用非捕獲元字符 '?:', '?=', or '?!' 來忽略對這部分正則表達式的保存。

所捕獲的每個子匹配都按照在正則表達式模式中從左至右所遇到的內容存儲。存儲子匹配的緩沖區編號從 1 開始,連續編號直至最大 99 個子表達式。每個緩沖區都可以使用 '\n' 訪問,其中 n 為一個標識特定緩沖區的一位或兩位十進制數。

后向引用一個最簡單,最有用的應用是提供了確定文字中連續出現兩個相同單詞的位置的能力。請看下面的句子:

Is is the cost of of gasoline going up up?

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

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

等價的 VBScript 表達式為:

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

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

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

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

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

最接近的等價  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")

請注意在 VBScript 代碼中,全局、大小寫敏感性以及多行標記都是使用 RegExp 對象的適當屬性來設置的。

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

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

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

下面的正則表達式可以提供這個功能。對 JScript,為:

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

對 VBScript 為:

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

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

將該正則表達式應用于上面所示的 URI 后,子匹配包含下述內容:

RegExp.$1 包含 "http"

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

RegExp.$3 包含 ":80"

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



snoics 2005-10-09 15:01 發表評論
]]>
常用正則表達式[轉http://www.tkk7.com/snoics/articles/15058.htmlsnoicssnoicsSun, 09 Oct 2005 06:57:00 GMThttp://www.tkk7.com/snoics/articles/15058.htmlhttp://www.tkk7.com/snoics/comments/15058.htmlhttp://www.tkk7.com/snoics/articles/15058.html#Feedback0http://www.tkk7.com/snoics/comments/commentRss/15058.htmlhttp://www.tkk7.com/snoics/services/trackbacks/15058.html一、驗證類
1、數字驗證內
1.1 整數
/^(-│+)?d+$/  不可以為空
/^[-+]?d*$/ 可以為空
1.2 大于0的整數 (用于傳來的ID的驗證)
/^d+$/
1.3 負整數的驗證
/^-d+$/
1.4 整數不能大于iMax
根據上面的正則可以寫出。
1.5 整數不能小于iMin
根據上面的正則可以寫出。
2、時間類
2.1 短時間,形如 (13:04:06)
    function isTime(str)
{
var a = str.match(/^(d)(:)?(d)2(d)$/);
if (a == null) {alert('輸入的參數不是時間格式'); return false;}
if (a[1]>24 ││ a[3]>60 ││ a[4]>60)
{
alert("時間格式不對");
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 長時間,形如 (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 只有小時和分鐘,形如(12:03)
3、表單類
3.1 所有的表單的值都不能為空
<input onblur="if(this.value.replace(/^s+│s+$/g,'')=='')alert('不能為空!')">

3.2 多行文本框的值不能為空。
3.3 多行文本框的值不能超過sMaxStrleng
//檢驗文本框中內容是否超長
function CheckTextareaLength(val, max_length) {
var str_area=document.forms[0].elements[val].value;
if (str_area!=null&&str_area.length > max_length)
{
alert("字段文字超長,最多可輸入" + max_length +"個字符,請重新輸入!");
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=="")? "請選擇 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 判斷復選框是否選擇.
function CheckCheckbox(val,msg1,msg2)
{
var is_radio=document.forms[0].elements[val];
var s_msg1=(msg1==null ││ msg1=="")? "請選擇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 復選框的全選,多選,全不選,反選
<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('有錯')">
4.2 判斷字符由字母和數字組成。
<input onblur="if(/[^0-9a-zA-Z]/g.test(this.value))alert('有錯')">

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

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

6、結合類
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 手機號碼的驗證
6.3 身份證的驗證
function isIdCardNo(num)
{
if (isNaN(num)) {alert("輸入的不是數字!"); 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("輸入的數字位數不對!"); 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("輸入的身份證號 "+ a[0] +" 里出生日期不對!"); return false;}
}
return true;
}
   另外一個
<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:非法地區";
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:非法證號";
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?BR><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后還能用的無邊框窗口??!
<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 電話號碼的驗證

要求:
  (1)電話號碼由數字、"("、")"和"-"構成
  (2)電話號碼為3到8位
  (3)如果電話號碼中包含有區號,那么區號為三位或四位
  (4)區號用"("、")"或"-"和其他部分隔開
  (5)移動電話號碼為11或12位,如果為12位,那么第一位為0
  (6)11位移動電話號碼的第一位和第二位為"13"
  (7)12位移動電話號碼的第二位和第三位為"13"
  根據這幾條規則,可以與出以下正則表達式:
  (^[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、時間與相關控件類
1.1 日歷
精華區的日歷

1.2 時間控件

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

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

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 禁止鼠標右鍵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、網頁設計類
5.1 連續滾動的文字,圖片(注意是連續的,兩段文字和圖片中沒有空白出現)
5.2 html編輯控件類
5.3 顏色選取框控件
5.4 下拉菜單
5.5 兩層或多層次的下拉菜單
5.6 仿IE菜單的按鈕。(效果如rongshuxa.com的導航欄目)
5.7 狀態欄,title欄的動態效果(例子很多,可以研究一下)
5.8 雙擊后,網頁自動滾屏
以上都是特效類,很容易找到的。
6、樹型結構。
6.1 asp+SQL版
6.2 asp+xml+sql版
6.3 java+sql或者java+sql+xml
7、無邊框效果的制作
8、連動下拉框技術
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,操縱客戶端注冊表類
<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層相關(拖拽、顯示、隱藏、移動、增加)
13,TABLAE相關(客戶端動態增加行列,模擬進度條,滾動列表等)
<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=>相關類,如播放器,flash與腳本互動等
16, 刷新/模擬無刷新 異步調用類(XMLHttp或iframe,frame)



snoics 2005-10-09 14:57 發表評論
]]>
JavaScript中的正則表達式解析 [轉]http://www.tkk7.com/snoics/articles/15057.htmlsnoicssnoicsSun, 09 Oct 2005 06:55:00 GMThttp://www.tkk7.com/snoics/articles/15057.htmlhttp://www.tkk7.com/snoics/comments/15057.htmlhttp://www.tkk7.com/snoics/articles/15057.html#Feedback0http://www.tkk7.com/snoics/comments/commentRss/15057.htmlhttp://www.tkk7.com/snoics/services/trackbacks/15057.html 

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

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

[注意] 文本格式的參數不用引號,而在用構造函數時的參數需要引號。如:/ab+c/i new RegExp("ab+c","i")是實現一樣的功能。在構造函數中,一些特殊字符需要進行轉意(在特殊字符前加"\")。如:re = new RegExp("\\w+")

正則表達式中的特殊字符

字符 含意
\

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

^ 匹配一個輸入或一行的開頭,/^a/匹配"an A",而不匹配"An a"
$ 匹配一個輸入或一行的結尾,/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),匹配這個集合中的任一一個字符(或元字符)
[^xyz] 不匹配這個集合中的任何一個字符
[\b] 匹配一個退格符
\b 匹配一個單詞的邊界
\B 匹配一個單詞的非邊界
\cX 這兒,X是一個控制符,/\cM/匹配Ctrl-M
\d 匹配一個字數字符,/\d/ = /[0-9]/
\D 匹配一個非字數字符,/\D/ = /[^0-9]/
\n 匹配一個換行符
\r 匹配一個回車符
\s 匹配一個空白字符,包括\n,\r,\f,\t,\v等
\S 匹配一個非空白字符,等于/[^\n\f\r\t\v]/
\t 匹配一個制表符
\v 匹配一個重直制表符
\w 匹配一個可以組成單詞的字符(alphanumeric,這是我的意譯,含數字),包括下劃線,如[\w]匹配"$5.98"中的5,等于[a-zA-Z0-9]
\W 匹配一個不可以組成單詞的字符,如[\W]匹配"$5.98"中的$,等于[^a-zA-Z0-9]。

說了這么多了,我們來看一些正則表達式的實際應用的例子:

E-mail地址驗證:
 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;");
 }

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

正則表達式對象的方法
方法 含義
compile      正則表達式比較
exec        執行查找
test        進行匹配
toSource      返回特定對象的定義(literal representing),其值可用來創建一個新的對象。重載Object.toSource方法得到的。
toString      返回特定對象的串。重載Object.toString方法得到的。
valueOf      返回特定對象的原始值。重載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 發表評論
]]>
正則表達式在javascript中的幾個實例2(轉)http://www.tkk7.com/snoics/articles/15056.htmlsnoicssnoicsSun, 09 Oct 2005 06:53:00 GMThttp://www.tkk7.com/snoics/articles/15056.htmlhttp://www.tkk7.com/snoics/comments/15056.htmlhttp://www.tkk7.com/snoics/articles/15056.html#Feedback0http://www.tkk7.com/snoics/comments/commentRss/15056.htmlhttp://www.tkk7.com/snoics/services/trackbacks/15056.html 

javascript正則表達式檢驗
/*********************************************************************************
* EO_JSLib.js
* javascript正則表達式檢驗
**********************************************************************************/

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

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

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

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

//校驗普通電話、傳真號碼:可以“+”開頭,除數字外,可含有“-”
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
}

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

//校驗郵政編碼
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
}

//校驗搜索關鍵字
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 發表評論
]]>
JAVA正則表達式4種常用功能 [轉]http://www.tkk7.com/snoics/articles/15055.htmlsnoicssnoicsSun, 09 Oct 2005 06:45:00 GMThttp://www.tkk7.com/snoics/articles/15055.htmlhttp://www.tkk7.com/snoics/comments/15055.htmlhttp://www.tkk7.com/snoics/articles/15055.html#Feedback0http://www.tkk7.com/snoics/comments/commentRss/15055.htmlhttp://www.tkk7.com/snoics/services/trackbacks/15055.html
JAVA正則表達式4種常用功能 
   
  正則表達式在字符串處理上有著強大的功能,sun在jdk1.4加入了對它的支持 
 
  下面簡單的說下它的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。如果想在查找時忽略大小寫,則可以寫成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)); 
 
 } 

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

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

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


snoics 2005-10-09 14:45 發表評論
]]>
java正則表達式; regular expression [轉]http://www.tkk7.com/snoics/articles/15054.htmlsnoicssnoicsSun, 09 Oct 2005 06:31:00 GMThttp://www.tkk7.com/snoics/articles/15054.htmlhttp://www.tkk7.com/snoics/comments/15054.htmlhttp://www.tkk7.com/snoics/articles/15054.html#Feedback0http://www.tkk7.com/snoics/comments/commentRss/15054.htmlhttp://www.tkk7.com/snoics/services/trackbacks/15054.html閱讀全文

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

這里有一些可能會遇到的正則表達式示例:

Visual Basic VBScript 匹配
Scripting Edition

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

/d{2}-d{5}/ "d{2}-d{5}" 驗證一個ID號碼是否由一個2位字,一
個連字符以及一個5位數字組成。

/<(.*)>.*</1>/ "<(.*)>.*</1>" 匹配一個 HTML 標記。


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

字符 描述

將下一個字符標記為一個特殊字符、或一個原義字符、或一個 后
向引用、或一個八進制轉義符。例如,’n’ 匹配字符 "n"?!痭’
匹配一個換行符。序列 ’’ 匹配 "" 而 "(" 則匹配 "("。

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

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

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

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

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

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

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

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

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

. 匹配除 "n" 之外的任何單個字符。要匹配包括 ’n’ 在內的任
何字符,請使用象 ’[.n]’ 的模式。

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

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

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

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

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

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

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

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

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

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

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

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

d 匹配一個數字字符。等價于 [0-9]。

D 匹配一個非數字字符。等價于 [^0-9]。

f 匹配一個換頁符。等價于 x0c 和 cL。

n 匹配一個換行符。等價于 x0a 和 cJ。

r 匹配一個回車符。等價于 x0d 和 cM。

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

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

t 匹配一個制表符。等價于 x09 和 cI。

v 匹配一個垂直制表符。等價于 x0b 和 cK。

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

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

xn 匹配 n,其中 n 為十六進制轉義值。十六進制轉義值必須為確
定的兩個數字長。例如, ’x41’ 匹配 "A"?!痻041’ 則等價
于 ’x04’ & "1"。正則表達式中可以使用 ASCII 編碼。.

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

n 標識一個八進制轉義值或一個后向引用。如果 n 之前至少 n
個獲取的子表達式,則 n 為后向引用。否則,如果 n 為八進制
數字 (0-7),則 n 為一個八進制轉義值。

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

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

un 匹配 n,其中 n 是一個用四個十六進制數字表示的Unicode字
符。例如, u00A9 匹配版權符號 (?)。


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

  The 30 Minute Regex Tutorial By Jim Hollenhorst

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

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

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

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

  接下來,就讓我們來體驗一些例子吧。

  一些簡單的例子
  假設要查找文章中Elvis后接有alive的文字符串的話,使用RE可能會經過下列的過程,括號是所下RE的意思:

  1. elvis (查找elvis)

  上述代表所要查找的字符順序為elvis。在.NET中可以設定乎略字符的大小寫,所以”Elvis”、”ELVIS”或者是”eLvIs”都是符合1所下的RE。但因為這只管字符出現的順序為elvis,所以pelvis也是符合1所下的RE??梢杂?的RE來改進。

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

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

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

  用簡單之特別字符就可以組成功能強大的RE,但也發現當使用越來越多的特別字符時,RE就會越來越難看得懂了。


再看看另外的例子
  組成有效的電話號碼

  假使要從網頁上收集顧客格式為xxx-xxxx的7位數字的電話號碼,其中x是數字,RE可能會這樣寫。

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

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

  RE的學習及測試工具 Expresso

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

  .NET中RE的基礎概念
  特殊字符

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

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

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

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

  下表為RE常用的特殊字符

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

  9. ^d{3}-d{4}$ (驗證七位數字之電話號碼)

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

  轉意字符(Escaped characters)

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

  重復前述項目

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

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

  再來試一些例子吧

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

  匹配某范圍的字符

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

  接下來再看一個比較初復雜查找電話號碼的RE例子

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

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

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

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

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

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

  擇一(Alternatives)

  有時會需要查找幾個特定的選擇,此時”|”這個特殊字符就派上用場了,舉例來說,要查找五個數字及九個數字(有”-”號)的郵政編碼。

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

  在使用Alternatives時需要注意的是前后的次序,因為RE在Alternatives中會優先選擇符合最左邊的項目,16中,如果把查找五個數字的項目放在前面,則這RE只會找到五個數字的郵政編碼。了解了擇一,可將14做更好的修正。

  17. ((d{3})|d{3})s?d{3}[- ]d{4} (十個數字的電話號碼)

  群組(Grouping)

  括號可以用來介定一個次描述,經由次描述的介定,可以針對次描述做重復或及他的處理。

  18. (d{1,3}.){3}d{1,3} (尋找網絡地址的簡單RE)

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

  但這樣會有個缺點,因為網絡地址數字最多只到255,但上述的RE只要是一到三位的數字都是符合的,所以這需要讓比較的數字小于256才行,但只單獨使用RE并無法做這樣的比較。在19中使用擇一來將地址的限制在所需要的范圍內,也就是0到255。

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

  有沒有發覺RE越來越像外星人說的話了?就以簡單的尋找網絡地址,直接看RE都滿難理解的哩。

  Expresso Analyzer View

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

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

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

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

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

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

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

  Positive Lookaround

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

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

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

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

  Negative Lookaround

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

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

  這樣的RE會有一個問題,因為[^u]要對應一個字符,所以若q是字的最后一個字母,[^u]這樣的下法就會將空格符對應下去,結果就有可能會符合二個字,比如說”Iraq haha”這樣的文字。使用Negative Lookaround就能解決這樣的問題。

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

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

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

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

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

  請批注(Comments Please)
  括號還有個特殊的用途就是用來包住批注,語法為”(?#comment)”,若設定”Ignore Pattern Whitespace”選項,則RE中的空格符當RE使用時會乎略。此選項設定時,”#”之后的文字會乎略。

  31. HTML卷標間的文字,加上批注

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

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

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

  若有一字符串是”aabab”,使用上述RE所得到的符合字符串就是”aabab”,因為這是尋找最多字符的字。有時希望是符合最少字符的字也就是lazy matching。只要將重復前述項目的表加上問號(?)就可以把它們全部變成lazy matching。因此”*?”代表的就是重復任意次數,但是使用最少重復的次數來符合。舉個例子來說:

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

  若有一字符串是”aabab”,使用上述RE第一個所得到的符合字符串就是”aab”再來是”ab”,因為這是尋找最少字符的字。

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

還有什么沒提到呢?

  到目前為止,已經提到了許多建立RE的元素,當然還有許多元素沒有提到,下表整理了一些沒提到的元素,在最左邊的字段的數字是說明在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選項)

  41 Z 字符串的結尾
  z 字符串的結尾

  42 G 目前查找的開始

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

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

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

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

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

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

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

snoics 2005-10-09 14:26 發表評論
]]>
正則表達式之道 [轉]http://www.tkk7.com/snoics/articles/15046.htmlsnoicssnoicsSun, 09 Oct 2005 06:04:00 GMThttp://www.tkk7.com/snoics/articles/15046.htmlhttp://www.tkk7.com/snoics/comments/15046.htmlhttp://www.tkk7.com/snoics/articles/15046.html#Feedback0http://www.tkk7.com/snoics/comments/commentRss/15046.htmlhttp://www.tkk7.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日


英文版原文

譯者按:原文因為年代久遠,文中很多鏈接早已過期(主要是關于vi、sed等工具的介紹和手冊),本譯文中已將此類鏈接刪除,如需檢查這些鏈接可以查看上面鏈接的原文。除此之外基本照原文直譯,括號中有“譯者按”的部分是譯者補充的說明。如有內容方面的問題請直接和Steve Mansor聯系,當然,如果你只寫中文,也可以和我聯系。


目 錄

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

 


什么是正則表達式

一個正則表達式,就是用某種模式去匹配一類字符串的一個公式。很多人因為它們看上去比較古怪而且復雜所以不敢去使用——很不幸,這篇文章也不能夠改變這一點,不過,經過一點點練習之后我就開始覺得這些復雜的表達式其實寫起來還是相當簡單的,而且,一旦你弄懂它們,你就能把數小時辛苦而且易錯的文本處理工作壓縮在幾分鐘(甚至幾秒鐘)內完成。正則表達式被各種文本編輯軟件、類庫(例如Rogue Wave的tools.h++)、腳本工具(像awk/grep/sed)廣泛的支持,而且像Microsoft的Visual C++這種交互式IDE也開始支持它了。

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

正則表達式基礎

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

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

要想真正的用好正則表達式,正確的理解元字符是最重要的事情。下表列出了所有的元字符和對它們的一個簡短的描述。

元字符   描述


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

 


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

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

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

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

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

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

簡單的例子

這里有一些有代表性的、比較簡單的例子。

vi 命令 作用


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

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

例1

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

之前   之后
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)

下面這條替換命令能夠實現這一魔法:

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

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

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

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

這個表達式我們已經分析到了:foo(([^,]*),這一段可以簡單的翻譯為“當你找到foo(就把其后直到第一個逗號之前的部分標記為1”。然后我們使用同樣的辦法標記第二個參數為2。對第三個參數的標記方法也是一樣,只是我們要搜索所有的字符直到右括號。我們并沒有必要去搜索第三個參數,因為我們不需要調整它的位置,但是這樣的模式能夠保證我們只去替換那些有三個參數的foo()方法調用,在foo()是一個重載(overoading)方法時這種明確的模式往往是比較保險的。然后,在替換部分,我們找到foo()的對應實例,然后利用標記好的部分進行替換,是的第一和第二個參數交換位置。

例2

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

這里有幾行我們現在的數據:

    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
    ...
我們希望把它變成這個樣子:
    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
    ...
我們將用兩個正則表達式來解決這個問題。第一個移動列和合并列,第二個用來去掉空格。

下面就是第一個替換命令:

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

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

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

例3

假設有一個多字符的片斷重復出現,例如:
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",以及任意數量連續出現的"really"字符串換成一個簡單的"very"(simple is good!),那么以下命令:
:%s/(really )(really )*/very /
就會把上述的文本變成:
Billy tried very hard
Sally tried very hard
Timmy tried very hard
Johnny tried very hard
表達式(really )*匹配0或多個連續的"really "(注意結尾有個空格),而(really )(really )* 匹配1個或多個連續的"really "實例。

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

Coming soon.

 


不同工具中的正則表達式

OK,你已經準備使用RE(regular expressions,正則表達式),但是你并準備使用vi。所以,在這里我們給出一些在其他工具中使用RE的例子。另外,我還會總結一下你在不同程序之間使用RE可能發現的區別。

當然,你也可以在Visual C++編輯器中使用RE。選擇Edit->Replace,然后選擇"Regular expression"選擇框,Find What輸入框對應上面介紹的vi命令:%s/pat1/pat2/g中的pat1部分,而Replace輸入框對應pat2部分。但是,為了得到vi的執行范圍和g選項,你要使用Replace All或者適當的手工Find Next and Replace(譯者按:知道為啥有人罵微軟弱智了吧,雖然VC中可以選中一個范圍的文本,然后在其中執行替換,但是總之不夠vi那么靈活和典雅)。

sed

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

這里是一些有趣的sed腳本,假定我們正在處理一個叫做price.txt的文件。注意這些編輯并不會改變源文件,sed只是處理源文件的每一行并把結果顯示在標準輸出中(當然很容易使用重定向來定制):

sed腳本   描述


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

awk

awk是一種編程語言,可以用來對文本數據進行復雜的分析和處理。可以在手冊中得到關于awk的詳細信息。這個古怪的名字是它作者們的姓的縮寫(Aho,Weinberger和Kernighan)。

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

awk腳本   描述


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

grep

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

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

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

grep命令   描述


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

egrep

egrep是grep的一個擴展版本,它在它的正則表達式中支持更多的元字符。下面的例子中我們假定在文件phone.txt中包含以下的文本,——其格式是姓加一個逗號,然后是名,然后是一個制表符,然后是電話號碼:
    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結束或者以W的行
egrep 'net(work)?s' report.txt 從report.txt中找到所有包含networks或者nets的行


正則表達式語法支持情況

命令或環境 . [ ] ^ $ ( ) { } ? + | ( )
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替換命令簡介

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

    s 表示其后是一個替換命令。

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

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

    g 可選標志,帶這個標志表示替換將針對行中每個匹配的串進行,否則則只替換行中第一個匹配串。

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

snoics 2005-10-09 14:04 發表評論
]]>
主站蜘蛛池模板: 亚洲激情中文字幕| 国产免费观看青青草原网站| 男人的天堂网免费网站| 草久免费在线观看网站| 日韩久久无码免费毛片软件| 免费国产va视频永久在线观看| 色五月五月丁香亚洲综合网| 婷婷国产偷v国产偷v亚洲| 色天使亚洲综合一区二区| 黄色网址大全免费| 一区二区三区精品高清视频免费在线播放 | 国产成人无码区免费A∨视频网站 国产成人涩涩涩视频在线观看免费 | 亚洲AV无码一区东京热| 亚洲va久久久噜噜噜久久天堂| 国产亚洲美女精品久久久久狼 | 国产精品免费看久久久无码| 亚洲AV无码成人精品区大在线| 爱情岛论坛网亚洲品质自拍| 亚洲色婷婷一区二区三区| 精品久久香蕉国产线看观看亚洲| 亚洲大成色www永久网站| 久久精品亚洲中文字幕无码麻豆| 亚洲短视频在线观看| 亚洲一区二区三区播放在线| 国产成人亚洲综合一区| 蜜臀亚洲AV无码精品国产午夜.| 黄色a级片免费看| 91视频精品全国免费观看| 久久久久国产精品免费看| 综合在线免费视频| 成在线人永久免费视频播放| AV在线播放日韩亚洲欧| 久久亚洲国产成人亚| 亚洲av永久无码精品三区在线4| 亚洲va中文字幕| 国产免费播放一区二区| 猫咪免费人成网站在线观看| 天天干在线免费视频| 久久亚洲AV永久无码精品| 亚洲自偷自拍另类图片二区| 亚洲AV无码之国产精品|