創(chuàng)建對(duì)象并寫入信息: import flash.net.SharedObject; var items_array:Array = new Array(101, 346, 483); var currentUserIsAdmin:Boolean = true; var currentUserName:String = "Ramona";
var my_so:SharedObject = SharedObject.getLocal("superfoo","/",false); my_so.data.itemNumbers = items_array; my_so.data.adminPrivileges = currentUserIsAdmin; my_so.data.userName = currentUserName; my_so.flush(1000); for (var prop in my_so.data) { ??? trace(prop+": "+my_so.data[prop]); }
寫在另外一個(gè)FLA文件中,讀取信息: import flash.net.SharedObject; var my_so:SharedObject = SharedObject.getLocal("superfoo","/",false);
for (var prop in my_so.data) { trace(prop+": "+my_so.data[prop]); }
文件保存到: C:\Documents and Settings\jianglang317\Application Data\Macromedia\Flash Player\#SharedObjects\FXHMK25Q\localhost
|
posted @
2008-10-23 15:23 華夢(mèng)行 閱讀(788) |
評(píng)論 (1) |
編輯 收藏
Action 類:
? Struts1要求Action類繼承一個(gè)抽象基類。Struts1的一個(gè)普遍問題是使用抽象類編程而不是接口。
? Struts 2 Action類可以實(shí)現(xiàn)一個(gè)Action接口,也可實(shí)現(xiàn)其他接口,使可選和定制的服務(wù)成為可能。Struts2提供一個(gè)ActionSupport基類去 實(shí)現(xiàn) 常用的接口。Action接口不是必須的,任何有execute標(biāo)識(shí)的POJO對(duì)象都可以用作Struts2的Action對(duì)象。
線程模式:
? Struts1 Action是單例模式并且必須是線程安全的,因?yàn)閮H有Action的一個(gè)實(shí)例來(lái)處理所有的請(qǐng)求。單例策略限制了Struts1 Action能作的事,并且要在開發(fā)時(shí)特別小心。Action資源必須是線程安全的或同步的。
? Struts2 Action對(duì)象為每一個(gè)請(qǐng)求產(chǎn)生一個(gè)實(shí)例,因此沒有線程安全問題。(實(shí)際上,servlet容器給每個(gè)請(qǐng)求產(chǎn)生許多可丟棄的對(duì)象,并且不會(huì)導(dǎo)致性能和垃圾回收問題)
Servlet 依賴:
? Struts1 Action 依賴于Servlet API ,因?yàn)楫?dāng)一個(gè)Action被調(diào)用時(shí)HttpServletRequest 和 HttpServletResponse 被傳遞給execute方法。
? Struts 2 Action不依賴于容器,允許Action脫離容器單獨(dú)被測(cè)試。如果需要,Struts2 Action仍然可以訪問初始的request和response。但是,其他的元素減少或者消除了直接訪問HttpServetRequest 和 HttpServletResponse的必要性。
可測(cè)性:
? 測(cè)試Struts1 Action的一個(gè)主要問題是execute方法暴露了servlet API(這使得測(cè)試要依賴于容器)。一個(gè)第三方擴(kuò)展--Struts TestCase--提供了一套Struts1的模擬對(duì)象(來(lái)進(jìn)行測(cè)試)。
? Struts 2 Action可以通過(guò)初始化、設(shè)置屬性、調(diào)用方法來(lái)測(cè)試,“依賴注入”支持也使測(cè)試更容易。
捕獲輸入:
? Struts1 使用ActionForm對(duì)象捕獲輸入。所有的ActionForm必須繼承一個(gè)基類。因?yàn)槠渌鸍avaBean不能用作ActionForm,開發(fā)者經(jīng) 常創(chuàng)建多余的類捕獲輸入。動(dòng)態(tài)Bean(DynaBeans)可以作為創(chuàng)建傳統(tǒng)ActionForm的選擇,但是,開發(fā)者可能是在重新描述(創(chuàng)建)已經(jīng)存 在的JavaBean(仍然會(huì)導(dǎo)致有冗余的javabean)。
? Struts 2直接使用Action屬性作為輸入屬性,消除了對(duì)第二個(gè)輸入對(duì)象的需求。輸入屬性可能是有自己(子)屬性的rich對(duì)象類型。Action屬性能夠通過(guò) web頁(yè)面上的taglibs訪問。Struts2也支持ActionForm模式。rich對(duì)象類型,包括業(yè)務(wù)對(duì)象,能夠用作輸入/輸出對(duì)象。這種 ModelDriven 特性簡(jiǎn)化了taglib對(duì)POJO輸入對(duì)象的引用。
表達(dá)式語(yǔ)言:
? Struts1 整合了JSTL,因此使用JSTL EL。這種EL有基本對(duì)象圖遍歷,但是對(duì)集合和索引屬性的支持很弱。
? Struts2可以使用JSTL,但是也支持一個(gè)更強(qiáng)大和靈活的表達(dá)式語(yǔ)言--"Object Graph Notation Language" (OGNL).
綁定值到頁(yè)面(view):
? Struts 1使用標(biāo)準(zhǔn)JSP機(jī)制把對(duì)象綁定到頁(yè)面中來(lái)訪問。
? Struts 2 使用 "ValueStack"技術(shù),使taglib能夠訪問值而不需要把你的頁(yè)面(view)和對(duì)象綁定起來(lái)。ValueStack策略允許通過(guò)一系列名稱相同但類型不同的屬性重用頁(yè)面(view)。
類型轉(zhuǎn)換:
? Struts 1 ActionForm 屬性通常都是String類型。Struts1使用Commons-Beanutils進(jìn)行類型轉(zhuǎn)換。每個(gè)類一個(gè)轉(zhuǎn)換器,對(duì)每一個(gè)實(shí)例來(lái)說(shuō)是不可配置的。
? Struts2 使用OGNL進(jìn)行類型轉(zhuǎn)換。提供基本和常用對(duì)象的轉(zhuǎn)換器。
校驗(yàn):
? Struts 1支持在ActionForm的validate方法中手動(dòng)校驗(yàn),或者通過(guò)Commons Validator的擴(kuò)展來(lái)校驗(yàn)。同一個(gè)類可以有不同的校驗(yàn)內(nèi)容,但不能校驗(yàn)子對(duì)象。
? Struts2支持通過(guò)validate方法和XWork校驗(yàn)框架來(lái)進(jìn)行校驗(yàn)。XWork校驗(yàn)框架使用為屬性類類型定義的校驗(yàn)和內(nèi)容校驗(yàn),來(lái)支持chain校驗(yàn)子屬性
Action執(zhí)行的控制:
? Struts1支持每一個(gè)模塊有單獨(dú)的Request Processors(生命周期),但是模塊中的所有Action必須共享相同的生命周期。
? Struts2支持通過(guò)攔截器堆棧(Interceptor Stacks)為每一個(gè)Action創(chuàng)建不同的生命周期。堆棧能夠根據(jù)需要和不同的Action一起使用。
posted @
2008-10-20 16:19 華夢(mèng)行 閱讀(228) |
評(píng)論 (0) |
編輯 收藏
?
李一男2003年在港灣給開發(fā)人員培訓(xùn)時(shí)的語(yǔ)錄,堪稱新時(shí)代的毛澤東思想。
【1】好好規(guī)劃自己的路,不要跟著感覺走!根據(jù)個(gè)人的理想決策安排,絕大部分人并不指望成為什么院士或教授,而是希望活得滋潤(rùn)一些,爽一些。那么,就需要慎重安排自己的軌跡。從哪個(gè)行業(yè)入手,逐漸對(duì)該行業(yè)深入了解,不要頻繁跳槽,特別是不要為了一點(diǎn)工資而轉(zhuǎn)移陣地,從長(zhǎng)遠(yuǎn)看,這點(diǎn)錢根本不算什么,當(dāng)你對(duì)一個(gè)行業(yè)有那么幾年的體會(huì),以后錢根本不是問題。頻繁地動(dòng)蕩不是上策,最后你對(duì)哪個(gè)行業(yè)都沒有摸透,永遠(yuǎn)是新手!
【2】可以做技術(shù),切不可沉湎于技術(shù)。千萬(wàn)不可一門心思鉆研技術(shù)!給自己很大壓力,如果你的心思全部放在這上面,那么注定你將成為孔乙己一類的人物!適可而止為之,因?yàn)榧夹g(shù)只不過(guò)是你今后前途的支柱之一,而且還不是最大的支柱,除非你只愿意到老還是個(gè)工程師!
【3】不要去做技術(shù)高手,只去做綜合素質(zhì)高手!在企業(yè)里混,我們時(shí)常瞧不起某人,說(shuō)他“什么都不懂,憑啥拿那么多錢,憑啥升官!”這是普遍的典型的工程師的迂腐之言。8051很牛嗎?人家能上去必然有他的本事,而且是你沒有的本事。你想想,老板搞經(jīng)營(yíng)那么多年,難道見識(shí)不如你這個(gè)新兵?人家或許善于管理,善于領(lǐng)會(huì)老板意圖,善于部門協(xié)調(diào)等等。因此務(wù)必培養(yǎng)自己多方面的能力,包括管理,親和力,察言觀色能力,攻關(guān)能力等,要成為綜合素質(zhì)的高手,則前途無(wú)量,否則只能躲在角落看示波器!技術(shù)以外的技能才是更重要的本事!!從古到今,美國(guó)日本,一律如此!
【4】多交社會(huì)三教九流的朋友!不要只和工程師交往,認(rèn)為有共同語(yǔ)言,其實(shí)更重要的是和其他類人物交往,如果你希望有朝一日當(dāng)老板或高層管理,那么你整日面對(duì)的就是這些人。了解他們的經(jīng)歷,思維習(xí)慣,愛好,學(xué)習(xí)他們處理問題的模式,了解社會(huì)各個(gè)角落的現(xiàn)象和問題,這是以后發(fā)展的巨大的本錢,沒有這些以后就會(huì)笨手笨腳,跌跌撞撞,遇到重重困難,交不少學(xué)費(fèi),成功的概率大大降低!
【5】知識(shí)涉獵不一定專,但一定要廣!多看看其他方面的書,金融,財(cái)會(huì),進(jìn)出口,稅務(wù),法律等等,為以后做一些積累,以后的用處會(huì)更大!會(huì)少交許多學(xué)費(fèi)!!
【6】抓住時(shí)機(jī)向技術(shù)管理或市場(chǎng)銷售方面的轉(zhuǎn)變!要想有前途就不能一直搞開發(fā),適當(dāng)時(shí)候要轉(zhuǎn)變?yōu)楣芾砘蜾N售,前途會(huì)更大,以前搞技術(shù)也沒有白搞,以后還用得著。搞管理可以培養(yǎng)自己的領(lǐng)導(dǎo)能力,搞銷售可以培養(yǎng)自己的市場(chǎng)概念和思維,同時(shí)為自己以后發(fā)展積累龐大的人 脈!應(yīng)該說(shuō)這才是前途的真正支柱。。?
【7】逐漸克服自己的心里弱點(diǎn)和性格缺陷!多疑,敏感,天真(貶義,并不可愛),猶豫不決,膽怯,多慮,臉皮太薄,心不夠黑,教條式思維。。。這些工程師普遍存在的性格弱點(diǎn)必須改變!很難嗎?只在床上想一想當(dāng)然不可能,去幫朋友守一個(gè)月地?cái)偅鼫?zhǔn)有效果,去實(shí)踐,而不要只想!不克服這些缺點(diǎn),一切不可能,甚至連項(xiàng)目經(jīng)理都當(dāng)不好--盡管你可能技術(shù)不錯(cuò)!
【8】工作的同時(shí)要為以后做準(zhǔn)備!建立自己的工作環(huán)境!及早為自己配置一個(gè)工作環(huán)境,裝備電腦,示波器(可以買個(gè)二手的),仿真器,編程器等,業(yè)余可以接點(diǎn)活,一方面接觸市場(chǎng),培養(yǎng)市場(chǎng)感覺,同時(shí)也積累資金,更重要的是準(zhǔn)備自己的產(chǎn)品,咱搞技術(shù)的沒有錢,只有技術(shù),技術(shù)的代表不是學(xué)歷和證書,而是產(chǎn)品,拿出象樣的產(chǎn)品,就可技術(shù)轉(zhuǎn)讓或與人合作搞企業(yè)!先把東西準(zhǔn)備好,等待機(jī)會(huì),否則,有了機(jī)會(huì)也抓不住!
【9】要學(xué)會(huì)善于推銷自己!不僅要能干,還要能說(shuō),能寫,善于利用一切機(jī)會(huì)推銷自己,樹立自己的品牌形象,很必要!要?jiǎng)?chuàng)造條件讓別人了解自己,不然老板怎么知道你能干?外面的投資人怎么相信你?提早把自己推銷出去,機(jī)會(huì)自然會(huì)來(lái)找你!搞個(gè)個(gè)人主頁(yè)是個(gè)好注意!!特別是培養(yǎng)自己在行業(yè)的名氣,有了名氣,高薪機(jī)會(huì)自不在話下,更重要的是有合作的機(jī)會(huì)...
【10】該出手時(shí)便出手!永遠(yuǎn)不可能有100%把握!!!條件差不多就要大膽去干,去闖出自己的事業(yè),不要猶豫,不要彷徨,干了不一定成功,但至少為下一次沖擊積累了經(jīng)驗(yàn),不干永遠(yuǎn)沒出息,而且要干成必然要經(jīng)歷失敗。不經(jīng)歷風(fēng)雨,怎么見彩虹,沒有人能隨隨便便成功 !
|
posted @
2008-10-20 09:39 華夢(mèng)行 閱讀(155) |
評(píng)論 (0) |
編輯 收藏
版本:v2.3 (2008-4-13) 作者:deerchao 轉(zhuǎn)載請(qǐng)注明來(lái)源
目錄
跳過(guò)目錄
-
本文目標(biāo)
-
如何使用本教程
-
正則表達(dá)式到底是什么東西?
-
入門
-
測(cè)試正則表達(dá)式
-
元字符
-
字符轉(zhuǎn)義
-
重復(fù)
-
字符類
-
分枝條件
-
反義
-
分組
-
后向引用
-
零寬斷言
-
負(fù)向零寬斷言
-
注釋
-
貪婪與懶惰
-
處理選項(xiàng)
-
平衡組/遞歸匹配
-
還有些什么東西沒提到
-
聯(lián)系作者
-
最后,來(lái)點(diǎn)廣告...
-
網(wǎng)上的資源及本文參考文獻(xiàn)
-
更新說(shuō)明
本文目標(biāo)
30分鐘內(nèi)讓你明白正則表達(dá)式是什么,并對(duì)它有一些基本的了解,讓你可以在自己的程序或網(wǎng)頁(yè)里使用它。
如何使用本教程
最重要的是——請(qǐng)給我30分鐘,如果你沒有使用正則表達(dá)式的經(jīng)驗(yàn),請(qǐng)不要試圖在30秒內(nèi)入門——除非你是超人 :)
別被下面那些復(fù)雜的表達(dá)式嚇倒,只要跟著我一步一步來(lái),你會(huì)發(fā)現(xiàn)正則表達(dá)式其實(shí)并沒有你想像中的那么困難。當(dāng)然,如果你看完了這篇教程之后,發(fā)現(xiàn)自己明白了很多,卻又幾乎什么都記不得,那也是很正常的——我認(rèn)為,沒接觸過(guò)正則表達(dá)式的人在看完這篇教程后,能把提到過(guò)的語(yǔ)法記住80%以上的可能性為零。這里只是讓你明白基本的原理,以后你還需要多練習(xí),多使用,才能熟練掌握正則表達(dá)式。
除了作為入門教程之外,本文還試圖成為可以在日常工作中使用的正則表達(dá)式語(yǔ)法參考手冊(cè)。就作者本人的經(jīng)歷來(lái)說(shuō),這個(gè)目標(biāo)還是完成得不錯(cuò)的——你看,我自己也沒能把所有的東西記下來(lái),不是嗎?
清除格式?文本格式約定:專業(yè)術(shù)語(yǔ)?元字符/語(yǔ)法格式?正則表達(dá)式?正則表達(dá)式中的一部分(用于分析)?對(duì)其進(jìn)行匹配的源字符串?對(duì)正則表達(dá)式或其中一部分的說(shuō)明
隱藏邊注?本文右邊有一些注釋,主要是用來(lái)提供一些相關(guān)信息,或者給沒有程序員背景的讀者解釋一些基本概念,通常可以忽略。
正則表達(dá)式到底是什么東西?
字符是計(jì)算機(jī)軟件處理文字時(shí)最基本的單位,可能是字母,數(shù)字,標(biāo)點(diǎn)符號(hào),空格,換行符,漢字等等。字符串是0個(gè)或更多個(gè)字符的序列。文本也就是文字,字符串。說(shuō)某個(gè)字符串匹配某個(gè)正則表達(dá)式,通常是指這個(gè)字符串里有一部分(或幾部分分別)能滿足表達(dá)式給出的條件。
在編寫處理字符串的程序或網(wǎng)頁(yè)時(shí),經(jīng)常會(huì)有查找符合某些復(fù)雜規(guī)則的字符串的需要。正則表達(dá)式就是用于描述這些規(guī)則的工具。換句話說(shuō),正則表達(dá)式就是記錄文本規(guī)則的代碼。
很可能你使用過(guò)Windows/Dos下用于文件查找的通配符(wildcard),也就是*和?。如果你想查找某個(gè)目錄下的所有的Word文檔的話,你會(huì)搜索*.doc。在這里,*會(huì)被解釋成任意的字符串。和通配符類似,正則表達(dá)式也是用來(lái)進(jìn)行文本匹配的工具,只不過(guò)比起通配符,它能更精確地描述你的需求——當(dāng)然,代價(jià)就是更復(fù)雜——比如你可以編寫一個(gè)正則表達(dá)式,用來(lái)查找所有以0開頭,后面跟著2-3個(gè)數(shù)字,然后是一個(gè)連字號(hào)“-”,最后是7或8位數(shù)字的字符串(像010-12345678或0376-7654321)。
入門
學(xué)習(xí)正則表達(dá)式的最好方法是從例子開始,理解例子之后再自己對(duì)例子進(jìn)行修改,實(shí)驗(yàn)。下面給出了不少簡(jiǎn)單的例子,并對(duì)它們作了詳細(xì)的說(shuō)明。
假設(shè)你在一篇英文小說(shuō)里查找hi,你可以使用正則表達(dá)式hi。
這幾乎是最簡(jiǎn)單的正則表達(dá)式了,它可以精確匹配這樣的字符串:由兩個(gè)字符組成,前一個(gè)字符是h,后一個(gè)是i。通常,處理正則表達(dá)式的工具會(huì)提供一個(gè)忽略大小寫的選項(xiàng),如果選中了這個(gè)選項(xiàng),它可以匹配hi,HI,Hi,hI這四種情況中的任意一種。
不幸的是,很多單詞里包含hi這兩個(gè)連續(xù)的字符,比如him,history,high等等。用hi來(lái)查找的話,這里邊的hi也會(huì)被找出來(lái)。如果要精確地查找hi這個(gè)單詞的話,我們應(yīng)該使用\bhi\b。
\b是正則表達(dá)式規(guī)定的一個(gè)特殊代碼(好吧,某些人叫它元字符,metacharacter),代表著單詞的開頭或結(jié)尾,也就是單詞的分界處。雖然通常英文的單詞是由空格,標(biāo)點(diǎn)符號(hào)或者換行來(lái)分隔的,但是\b并不匹配這些單詞分隔字符中的任何一個(gè),它只匹配一個(gè)位置。
如果需要更精確的說(shuō)法,\b匹配這樣的位置:它的前一個(gè)字符和后一個(gè)字符不全是(一個(gè)是,一個(gè)不是或不存在)\w。
假如你要找的是hi后面不遠(yuǎn)處跟著一個(gè)Lucy,你應(yīng)該用\bhi\b.*\bLucy\b。
這里,.是另一個(gè)元字符,匹配除了換行符以外的任意字符。*同樣是元字符,不過(guò)它代表的不是字符,也不是位置,而是數(shù)量——它指定*前邊的內(nèi)容可以連續(xù)重復(fù)出現(xiàn)任意次以使整個(gè)表達(dá)式得到匹配。因此,.*連在一起就意味著任意數(shù)量的不包含換行的字符。現(xiàn)在\bhi\b.*\bLucy\b的意思就很明顯了:先是一個(gè)單詞hi,然后是任意個(gè)任意字符(但不能是換行),最后是Lucy這個(gè)單詞。
換行符就是'\n',ASCII編碼為10(十六進(jìn)制0x0A)的字符。
如果同時(shí)使用其它元字符,我們就能構(gòu)造出功能更強(qiáng)大的正則表達(dá)式。比如下面這個(gè)例子:
0\d\d-\d\d\d\d\d\d\d\d匹配這樣的字符串:以0開頭,然后是兩個(gè)數(shù)字,然后是一個(gè)連字號(hào)“-”,最后是8個(gè)數(shù)字(也就是中國(guó)的電話號(hào)碼。當(dāng)然,這個(gè)例子只能匹配區(qū)號(hào)為3位的情形)。
這里的\d是個(gè)新的元字符,匹配一位數(shù)字(0,或1,或2,或……)。-不是元字符,只匹配它本身——連字符或者減號(hào)。
為了避免那么多煩人的重復(fù),我們也可以這樣寫這個(gè)表達(dá)式:0\d{2}-\d{8}。 這里\d后面的{2}({8})的意思是前面\d必須連續(xù)重復(fù)匹配2次(8次)。
測(cè)試正則表達(dá)式
如果你不覺得正則表達(dá)式很難讀寫的話,要么你是一個(gè)天才,要么,你不是地球人。正則表達(dá)式的語(yǔ)法很令人頭疼,即使對(duì)經(jīng)常使用它的人來(lái)說(shuō)也是如此。由于難于讀寫,容易出錯(cuò),所以找一種工具對(duì)正則表達(dá)式進(jìn)行測(cè)試是很有必要的。
由于在不同的環(huán)境下正則表達(dá)式的一些細(xì)節(jié)是不相同的,本教程介紹的是微軟 .Net Framework 2.0下正則表達(dá)式的行為,所以,我向你介紹一個(gè).Net下的工具Regex Tester。首先你確保已經(jīng)安裝了.Net Framework 2.0,然后下載Regex Tester。這是個(gè)綠色軟件,下載完后打開壓縮包,直接運(yùn)行RegexTester.exe就可以了。
下面是Regex Tester運(yùn)行時(shí)的截圖:
元字符
現(xiàn)在你已經(jīng)知道幾個(gè)很有用的元字符了,如\b,.,*,還有\d.正則表達(dá)式里還有更多的元字符,比如\s匹配任意的空白符,包括空格,制表符(Tab),換行符,中文全角空格等。\w匹配字母或數(shù)字或下劃線或漢字等。
對(duì)中文/漢字的特殊處理是由.Net提供的正則表達(dá)式引擎支持的,其它環(huán)境下的具體情況請(qǐng)查看相關(guān)文檔。
下面來(lái)看看更多的例子:
\ba\w*\b匹配以字母a開頭的單詞——先是某個(gè)單詞開始處(\b),然后是字母a,然后是任意數(shù)量的字母或數(shù)字(\w*),最后是單詞結(jié)束處(\b)。
好吧,現(xiàn)在我們說(shuō)說(shuō)正則表達(dá)式里的單詞是什么意思吧:就是多于一個(gè)的連續(xù)的\w。不錯(cuò),這與學(xué)習(xí)英文時(shí)要背的成千上萬(wàn)個(gè)同名的東西的確關(guān)系不大 :)
\d+匹配1個(gè)或更多連續(xù)的數(shù)字。這里的+是和*類似的元字符,不同的是*匹配重復(fù)任意次(可能是0次),而+則匹配重復(fù)1次或更多次。
\b\w{6}\b 匹配剛好6個(gè)字母/數(shù)字的單詞。
表1.常用的元字符
代碼 |
說(shuō)明 |
.
|
匹配除換行符以外的任意字符
|
\w
|
匹配字母或數(shù)字或下劃線或漢字
|
\s
|
匹配任意的空白符
|
\d
|
匹配數(shù)字
|
\b
|
匹配單詞的開始或結(jié)束
|
^
|
匹配字符串的開始
|
$
|
匹配字符串的結(jié)束
|
元字符^(和數(shù)字6在同一個(gè)鍵位上的符號(hào))和$都匹配一個(gè)位置,這和\b有點(diǎn)類似。^匹配你要用來(lái)查找的字符串的開頭,$匹配結(jié)尾。這兩個(gè)代碼在驗(yàn)證輸入的內(nèi)容時(shí)非常有用,比如一個(gè)網(wǎng)站如果要求你填寫的QQ號(hào)必須為5位到12位數(shù)字時(shí),可以使用:^\d{5,12}$。
這里的{5,12}和前面介紹過(guò)的{2}是類似的,只不過(guò){2}匹配只能不多不少重復(fù)2次,{5,12}則是重復(fù)的次數(shù)不能少于5次,不能多于12次,否則都不匹配。
因?yàn)槭褂昧?span>^和$,所以輸入的整個(gè)字符串都要用來(lái)和\d{5,12}來(lái)匹配,也就是說(shuō)整個(gè)輸入必須是5到12個(gè)數(shù)字,因此如果輸入的QQ號(hào)能匹配這個(gè)正則表達(dá)式的話,那就符合要求了。
和忽略大小寫的選項(xiàng)類似,有些正則表達(dá)式處理工具還有一個(gè)處理多行的選項(xiàng)。如果選中了這個(gè)選項(xiàng),^和$的意義就變成了匹配行的開始處和結(jié)束處。
字符轉(zhuǎn)義
如果你想查找元字符本身的話,比如你查找.,或者*,就出現(xiàn)了問題:你沒辦法指定它們,因?yàn)樗鼈儠?huì)被解釋成別的意思。這時(shí)你就得使用\來(lái)取消這些字符的特殊意義。因此,你應(yīng)該使用\.和\*。當(dāng)然,要查找\本身,你也得用\\.
例如:unibetter\.com匹配unibetter.com,C:\\Windows匹配C:\Windows。
重復(fù)
你已經(jīng)看過(guò)了前面的*,+,{2},{5,12}這幾個(gè)匹配重復(fù)的方式了。下面是正則表達(dá)式中所有的限定符(指定數(shù)量的代碼,例如*,{5,12}等):
表2.常用的限定符
代碼/語(yǔ)法 |
說(shuō)明 |
*
|
重復(fù)零次或更多次
|
+
|
重復(fù)一次或更多次
|
?
|
重復(fù)零次或一次
|
{n}
|
重復(fù)n次
|
{n,}
|
重復(fù)n次或更多次
|
{n,m}
|
重復(fù)n到m次
|
下面是一些使用重復(fù)的例子:
Windows\d+匹配Windows后面跟1個(gè)或更多數(shù)字
^\w+匹配一行的第一個(gè)單詞(或整個(gè)字符串的第一個(gè)單詞,具體匹配哪個(gè)意思得看選項(xiàng)設(shè)置)
字符類
要想查找數(shù)字,字母或數(shù)字,空白是很簡(jiǎn)單的,因?yàn)橐呀?jīng)有了對(duì)應(yīng)這些字符集合的元字符,但是如果你想匹配沒有預(yù)定義元字符的字符集合(比如元音字母a,e,i,o,u),應(yīng)該怎么辦?
很簡(jiǎn)單,你只需要在方括號(hào)里列出它們就行了,像[aeiou]就匹配任何一個(gè)英文元音字母,[.?!]匹配標(biāo)點(diǎn)符號(hào)(.或?或!)。
我們也可以輕松地指定一個(gè)字符范圍,像[0-9]代表的含意與\d就是完全一致的:一位數(shù)字;同理[a-z0-9A-Z_]也完全等同于\w(如果只考慮英文的話)。
下面是一個(gè)更復(fù)雜的表達(dá)式:\(?0\d{2}[) -]?\d{8}。
“(”和“)”也是元字符,后面的分組節(jié)里會(huì)提到,所以在這里需要使用轉(zhuǎn)義。
這個(gè)表達(dá)式可以匹配幾種格式的電話號(hào)碼,像(010)88886666,或022-22334455,或02912345678等。我們對(duì)它進(jìn)行一些分析吧:首先是一個(gè)轉(zhuǎn)義字符\(,它能出現(xiàn)0次或1次(?),然后是一個(gè)0,后面跟著2個(gè)數(shù)字(\d{2}),然后是)或-或空格中的一個(gè),它出現(xiàn)1次或不出現(xiàn)(?),最后是8個(gè)數(shù)字(\d{8})。
分枝條件
不幸的是,剛才那個(gè)表達(dá)式也能匹配010)12345678或(022-87654321這樣的“不正確”的格式。要解決這個(gè)問題,我們需要用到分枝條件。正則表達(dá)式里的分枝條件指的是有幾種規(guī)則,如果滿足其中任意一種規(guī)則都應(yīng)該當(dāng)成匹配,具體方法是用|把不同的規(guī)則分隔開。聽不明白?沒關(guān)系,看例子:
0\d{2}-\d{8}|0\d{3}-\d{7}這個(gè)表達(dá)式能匹配兩種以連字號(hào)分隔的電話號(hào)碼:一種是三位區(qū)號(hào),8位本地號(hào)(如010-12345678),一種是4位區(qū)號(hào),7位本地號(hào)(0376-2233445)。
\(0\d{2}\)[- ]?\d{8}|0\d{2}[- ]?\d{8}這個(gè)表達(dá)式匹配3位區(qū)號(hào)的電話號(hào)碼,其中區(qū)號(hào)可以用小括號(hào)括起來(lái),也可以不用,區(qū)號(hào)與本地號(hào)間可以用連字號(hào)或空格間隔,也可以沒有間隔。你可以試試用分枝條件把這個(gè)表達(dá)式擴(kuò)展成也支持4位區(qū)號(hào)的。
\d{5}-\d{4}|\d{5}這個(gè)表達(dá)式用于匹配美國(guó)的郵政編碼。美國(guó)郵編的規(guī)則是5位數(shù)字,或者用連字號(hào)間隔的9位數(shù)字。之所以要給出這個(gè)例子是因?yàn)樗苷f(shuō)明一個(gè)問題:使用分枝條件時(shí),要注意各個(gè)條件的順序。如果你把它改成\d{5}|\d{5}-\d{4}的話,那么就只會(huì)匹配5位的郵編(以及9位郵編的前5位)。原因是匹配分枝條件時(shí),將會(huì)從左到右地測(cè)試每個(gè)條件,如果滿足了某個(gè)分枝的話,就不會(huì)去再管其它的條件了。
分組
我們已經(jīng)提到了怎么重復(fù)單個(gè)字符(直接在字符后面加上限定符就行了);但如果想要重復(fù)多個(gè)字符又該怎么辦?你可以用小括號(hào)來(lái)指定子表達(dá)式(也叫做分組),然后你就可以指定這個(gè)子表達(dá)式的重復(fù)次數(shù)了,你也可以對(duì)子表達(dá)式進(jìn)行其它一些操作(后面會(huì)有介紹)。
(\d{1,3}\.){3}\d{1,3}是一個(gè)簡(jiǎn)單的IP地址匹配表達(dá)式。要理解這個(gè)表達(dá)式,請(qǐng)按下列順序分析它:\d{1,3}匹配1到3位的數(shù)字,(\d{1,3}\.){3}匹配三位數(shù)字加上一個(gè)英文句號(hào)(這個(gè)整體也就是這個(gè)分組)重復(fù)3次,最后再加上一個(gè)一到三位的數(shù)字(\d{1,3})。
IP地址中每個(gè)數(shù)字都不能大于255,大家千萬(wàn)不要被《24》第三季的編劇給忽悠了...
不幸的是,它也將匹配256.300.888.999這種不可能存在的IP地址。如果能使用算術(shù)比較的話,或許能簡(jiǎn)單地解決這個(gè)問題,但是正則表達(dá)式中并不提供關(guān)于數(shù)學(xué)的任何功能,所以只能使用冗長(zhǎng)的分組,選擇,字符類來(lái)描述一個(gè)正確的IP地址:((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)。
理解這個(gè)表達(dá)式的關(guān)鍵是理解2[0-4]\d|25[0-5]|[01]?\d\d?,這里我就不細(xì)說(shuō)了,你自己應(yīng)該能分析得出來(lái)它的意義。
反義
有時(shí)需要查找不屬于某個(gè)能簡(jiǎn)單定義的字符類的字符。比如想查找除了數(shù)字以外,其它任意字符都行的情況,這時(shí)需要用到反義:
表3.常用的反義代碼
代碼/語(yǔ)法 |
說(shuō)明 |
\W
|
匹配任意不是字母,數(shù)字,下劃線,漢字的字符
|
\S
|
匹配任意不是空白符的字符
|
\D
|
匹配任意非數(shù)字的字符
|
\B
|
匹配不是單詞開頭或結(jié)束的位置
|
[^x]
|
匹配除了x以外的任意字符
|
[^aeiou]
|
匹配除了aeiou這幾個(gè)字母以外的任意字符
|
例子:\S+匹配不包含空白符的字符串。
<a[^>]+>匹配用尖括號(hào)括起來(lái)的以a開頭的字符串。
后向引用
使用小括號(hào)指定一個(gè)子表達(dá)式后,匹配這個(gè)子表達(dá)式的文本(也就是此分組捕獲的內(nèi)容)可以在表達(dá)式或其它程序中作進(jìn)一步的處理。默認(rèn)情況下,每個(gè)分組會(huì)自動(dòng)擁有一個(gè)組號(hào),規(guī)則是:從左向右,以分組的左括號(hào)為標(biāo)志,第一個(gè)出現(xiàn)的分組的組號(hào)為1,第二個(gè)為2,以此類推。
后向引用用于重復(fù)搜索前面某個(gè)分組匹配的文本。例如,\1代表分組1匹配的文本。難以理解?請(qǐng)看示例:
\b(\w+)\b\s+\1\b可以用來(lái)匹配重復(fù)的單詞,像go go, 或者kitty kitty。這個(gè)表達(dá)式首先是一個(gè)單詞,也就是單詞開始處和結(jié)束處之間的多于一個(gè)的字母或數(shù)字(\b(\w+)\b),這個(gè)單詞會(huì)被捕獲到編號(hào)為1的分組中,然后是1個(gè)或幾個(gè)空白符(\s+),最后是分組1中捕獲的內(nèi)容(也就是前面匹配的那個(gè)單詞)(\1)。
你也可以自己指定子表達(dá)式的組名。要指定一個(gè)子表達(dá)式的組名,請(qǐng)使用這樣的語(yǔ)法:(?<Word>\w+)(或者把尖括號(hào)換成'也行:(?'Word'\w+)),這樣就把\w+的組名指定為Word了。要反向引用這個(gè)分組捕獲的內(nèi)容,你可以使用\k<Word>,所以上一個(gè)例子也可以寫成這樣:\b(?<Word>\w+)\b\s+\k<Word>\b。
使用小括號(hào)的時(shí)候,還有很多特定用途的語(yǔ)法。下面列出了最常用的一些:
表4.常用分組語(yǔ)法
分類 |
代碼/語(yǔ)法 |
說(shuō)明 |
捕獲 |
(exp)
|
匹配exp,并捕獲文本到自動(dòng)命名的組里
|
(?<name>exp)
|
匹配exp,并捕獲文本到名稱為name的組里,也可以寫成(?'name'exp)
|
(?:exp)
|
匹配exp,不捕獲匹配的文本,也不給此分組分配組號(hào)
|
零寬斷言 |
(?=exp)
|
匹配exp前面的位置
|
(?<=exp)
|
匹配exp后面的位置
|
(?!exp)
|
匹配后面跟的不是exp的位置
|
(?<!exp)
|
匹配前面不是exp的位置
|
注釋 |
(?#comment)
|
這種類型的分組不對(duì)正則表達(dá)式的處理產(chǎn)生任何影響,用于提供注釋讓人閱讀
|
我們已經(jīng)討論了前兩種語(yǔ)法。第三個(gè)(?:exp)不會(huì)改變正則表達(dá)式的處理方式,只是這樣的組匹配的內(nèi)容不會(huì)像前兩種那樣被捕獲到某個(gè)組里面,也不會(huì)擁有組號(hào)。
零寬斷言
地球人,是不是覺得這些術(shù)語(yǔ)名稱太復(fù)雜,太難記了?我也和你一樣。知道有這么一種東西就行了,它叫什么,隨它去吧!“無(wú)名,萬(wàn)物之始...”
接下來(lái)的四個(gè)用于查找在某些內(nèi)容(但并不包括這些內(nèi)容)之前或之后的東西,也就是說(shuō)它們像\b,^,$那樣用于指定一個(gè)位置,這個(gè)位置應(yīng)該滿足一定的條件(即斷言),因此它們也被稱為零寬斷言。最好還是拿例子來(lái)說(shuō)明吧:
斷言用來(lái)聲明一個(gè)應(yīng)該為真的事實(shí)。正則表達(dá)式中只有當(dāng)斷言為真時(shí)才會(huì)繼續(xù)進(jìn)行匹配。
(?=exp)也叫零寬度正預(yù)測(cè)先行斷言,它斷言自身出現(xiàn)的位置的后面能匹配表達(dá)式exp。比如\b\w+(?=ing\b),匹配以ing結(jié)尾的單詞的前面部分(除了ing以外的部分),如查找I'm singing while you're dancing.時(shí),它會(huì)匹配sing和danc。
(?<=exp)也叫零寬度正回顧后發(fā)斷言,它斷言自身出現(xiàn)的位置的前面能匹配表達(dá)式exp。比如(?<=\bre)\w+\b會(huì)匹配以re開頭的單詞的后半部分(除了re以外的部分),例如在查找reading a book時(shí),它匹配ading。
假如你想要給一個(gè)很長(zhǎng)的數(shù)字中每三位間加一個(gè)逗號(hào)(當(dāng)然是從右邊加起了),你可以這樣查找需要在前面和里面添加逗號(hào)的部分:((?<=\d)\d{3})*\b,用它對(duì)1234567890進(jìn)行查找時(shí)結(jié)果是234567890。
下面這個(gè)例子同時(shí)使用了這兩種斷言:(?<=\s)\d+(?=\s)匹配以空白符間隔的數(shù)字(再次強(qiáng)調(diào),不包括這些空白符)。
負(fù)向零寬斷言
前面我們提到過(guò)怎么查找不是某個(gè)字符或不在某個(gè)字符類里的字符的方法(反義)。但是如果我們只是想要確保某個(gè)字符沒有出現(xiàn),但并不想去匹配它時(shí)怎么辦?例如,如果我們想查找這樣的單詞--它里面出現(xiàn)了字母q,但是q后面跟的不是字母u,我們可以嘗試這樣:
\b\w*q[^u]\w*\b匹配包含后面不是字母u的字母q的單詞。但是如果多做測(cè)試(或者你思維足夠敏銳,直接就觀察出來(lái)了),你會(huì)發(fā)現(xiàn),如果q出現(xiàn)在單詞的結(jié)尾的話,像Iraq,Benq,這個(gè)表達(dá)式就會(huì)出錯(cuò)。這是因?yàn)?span>[^u]總要匹配一個(gè)字符,所以如果q是單詞的最后一個(gè)字符的話,后面的[^u]將會(huì)匹配q后面的單詞分隔符(可能是空格,或者是句號(hào)或其它的什么),后面的\w*\b將會(huì)匹配下一個(gè)單詞,于是\b\w*q[^u]\w*\b就能匹配整個(gè)Iraq fighting。負(fù)向零寬斷言能解決這樣的問題,因?yàn)樗黄ヅ湟粋€(gè)位置,并不消費(fèi)任何字符。現(xiàn)在,我們可以這樣來(lái)解決這個(gè)問題:\b\w*q(?!u)\w*\b。
零寬度負(fù)預(yù)測(cè)先行斷言
(?!exp),斷言此位置的后面不能匹配表達(dá)式exp。例如:\d{3}(?!\d)匹配三位數(shù)字,而且這三位數(shù)字的后面不能是數(shù)字;\b((?!abc)\w)+\b匹配不包含連續(xù)字符串a(chǎn)bc的單詞。
同理,我們可以用(?<!exp),零寬度正回顧后發(fā)斷言來(lái)斷言此位置的前面不能匹配表達(dá)式exp:(?<![a-z])\d{7}匹配前面不是小寫字母的七位數(shù)字。
請(qǐng)?jiān)敿?xì)分析表達(dá)式(?<=<(\w+)>).*(?=<\/\1>),這個(gè)表達(dá)式最能表現(xiàn)零寬斷言的真正用途。
一個(gè)更復(fù)雜的例子:(?<=<(\w+)>).*(?=<\/\1>)匹配不包含屬性的簡(jiǎn)單HTML標(biāo)簽內(nèi)里的內(nèi)容。(<?(\w+)>)指定了這樣的前綴:被尖括號(hào)括起來(lái)的單詞(比如可能是<b>),然后是.*(任意的字符串),最后是一個(gè)后綴(?=<\/\1>)。注意后綴里的\/,它用到了前面提過(guò)的字符轉(zhuǎn)義;\1則是一個(gè)反向引用,引用的正是捕獲的第一組,前面的(\w+)匹配的內(nèi)容,這樣如果前綴實(shí)際上是<b>的話,后綴就是</b>了。整個(gè)表達(dá)式匹配的是<b>和</b>之間的內(nèi)容(再次提醒,不包括前綴和后綴本身)。
注釋
小括號(hào)的另一種用途是通過(guò)語(yǔ)法(?#comment)來(lái)包含注釋。例如:2[0-4]\d(?#200-249)|25[0-5](?#250-255)|[01]?\d\d?(?#0-199)。
要包含注釋的話,最好是啟用“忽略模式里的空白符”選項(xiàng),這樣在編寫表達(dá)式時(shí)能任意的添加空格,Tab,換行,而實(shí)際使用時(shí)這些都將被忽略。啟用這個(gè)選項(xiàng)后,在#后面到這一行結(jié)束的所有文本都將被當(dāng)成注釋忽略掉。例如,我們可以前面的一個(gè)表達(dá)式寫成這樣:
(?<= # 斷言要匹配的文本的前綴
<(\w+)> # 查找尖括號(hào)括起來(lái)的字母或數(shù)字(即HTML/XML標(biāo)簽)
) # 前綴結(jié)束
.* # 匹配任意文本
(?= # 斷言要匹配的文本的后綴
<\/\1> # 查找尖括號(hào)括起來(lái)的內(nèi)容:前面是一個(gè)"/",后面是先前捕獲的標(biāo)簽
) # 后綴結(jié)束
貪婪與懶惰
當(dāng)正則表達(dá)式中包含能接受重復(fù)的限定符時(shí),通常的行為是(在使整個(gè)表達(dá)式能得到匹配的前提下)匹配盡可能多的字符。考慮這個(gè)表達(dá)式:a.*b,它將會(huì)匹配最長(zhǎng)的以a開始,以b結(jié)束的字符串。如果用它來(lái)搜索aabab的話,它會(huì)匹配整個(gè)字符串aabab。這被稱為貪婪匹配。
有時(shí),我們更需要懶惰匹配,也就是匹配盡可能少的字符。前面給出的限定符都可以被轉(zhuǎn)化為懶惰匹配模式,只要在它后面加上一個(gè)問號(hào)?。這樣.*?就意味著匹配任意數(shù)量的重復(fù),但是在能使整個(gè)匹配成功的前提下使用最少的重復(fù)。現(xiàn)在看看懶惰版的例子吧:
a.*?b匹配最短的,以a開始,以b結(jié)束的字符串。如果把它應(yīng)用于aabab的話,它會(huì)匹配aab(第一到第三個(gè)字符)和ab(第四到第五個(gè)字符)。
為什么第一個(gè)匹配是aab(第一到第三個(gè)字符)而不是ab(第二到第三個(gè)字符)?簡(jiǎn)單地說(shuō),因?yàn)檎齽t表達(dá)式有另一條規(guī)則,比懶惰/貪婪規(guī)則的優(yōu)先級(jí)更高:最先開始的匹配擁有最高的優(yōu)先權(quán)——The match that begins earliest wins。
表5.懶惰限定符
代碼/語(yǔ)法 |
說(shuō)明 |
*?
|
重復(fù)任意次,但盡可能少重復(fù)
|
+?
|
重復(fù)1次或更多次,但盡可能少重復(fù)
|
??
|
重復(fù)0次或1次,但盡可能少重復(fù)
|
{n,m}?
|
重復(fù)n到m次,但盡可能少重復(fù)
|
{n,}?
|
重復(fù)n次以上,但盡可能少重復(fù)
|
處理選項(xiàng)
在C#中,你可以使用Regex(String, RegexOptions)構(gòu)造函數(shù)來(lái)設(shè)置正則表達(dá)式的處理選項(xiàng)。如:Regex regex = new Regex("\ba\w{6}\b", RegexOptions.IgnoreCase);
上面介紹了幾個(gè)選項(xiàng)如忽略大小寫,處理多行等,這些選項(xiàng)能用來(lái)改變處理正則表達(dá)式的方式。下面是.Net中常用的正則表達(dá)式選項(xiàng):
表6.常用的處理選項(xiàng)
名稱 |
說(shuō)明 |
IgnoreCase(忽略大小寫) |
匹配時(shí)不區(qū)分大小寫。 |
Multiline(多行模式) |
更改^和$的含義,使它們分別在任意一行的行首和行尾匹配,而不僅僅在整個(gè)字符串的開頭和結(jié)尾匹配。(在此模式下,$的精確含意是:匹配\n之前的位置以及字符串結(jié)束前的位置.) |
Singleline(單行模式) |
更改.的含義,使它與每一個(gè)字符匹配(包括換行符\n)。 |
IgnorePatternWhitespace(忽略空白) |
忽略表達(dá)式中的非轉(zhuǎn)義空白并啟用由#標(biāo)記的注釋。 |
RightToLeft(從右向左查找) |
匹配從右向左而不是從左向右進(jìn)行。 |
ExplicitCapture(顯式捕獲) |
僅捕獲已被顯式命名的組。 |
ECMAScript(JavaScript兼容模式) |
使表達(dá)式的行為與它在JavaScript里的行為一致。 |
一個(gè)經(jīng)常被問到的問題是:是不是只能同時(shí)使用多行模式和單行模式中的一種?答案是:不是。這兩個(gè)選項(xiàng)之間沒有任何關(guān)系,除了它們的名字比較相似(以至于讓人感到疑惑)以外。
平衡組/遞歸匹配
這里介紹的平衡組語(yǔ)法是由.Net Framework支持的;其它語(yǔ)言/庫(kù)不一定支持這種功能,或者支持此功能但需要使用不同的語(yǔ)法。
有時(shí)我們需要匹配像( 100 * ( 50 + 15 ) )這樣的可嵌套的層次性結(jié)構(gòu),這時(shí)簡(jiǎn)單地使用\(.+\)則只會(huì)匹配到最左邊的左括號(hào)和最右邊的右括號(hào)之間的內(nèi)容(這里我們討論的是貪婪模式,懶惰模式也有下面的問題)。假如原來(lái)的字符串里的左括號(hào)和右括號(hào)出現(xiàn)的次數(shù)不相等,比如( 5 / ( 3 + 2 ) ) ),那我們的匹配結(jié)果里兩者的個(gè)數(shù)也不會(huì)相等。有沒有辦法在這樣的字符串里匹配到最長(zhǎng)的,配對(duì)的括號(hào)之間的內(nèi)容呢?
為了避免(和\(把你的大腦徹底搞糊涂,我們還是用尖括號(hào)代替圓括號(hào)吧。現(xiàn)在我們的問題變成了如何把xx <aa <bbb> <bbb> aa> yy這樣的字符串里,最長(zhǎng)的配對(duì)的尖括號(hào)內(nèi)的內(nèi)容捕獲出來(lái)?
這里需要用到以下的語(yǔ)法構(gòu)造:
-
(?'group') 把捕獲的內(nèi)容命名為group,并壓入堆棧(Stack)
-
(?'-group') 從堆棧上彈出最后壓入堆棧的名為group的捕獲內(nèi)容,如果堆棧本來(lái)為空,則本分組的匹配失敗
-
(?(group)yes|no) 如果堆棧上存在以名為group的捕獲內(nèi)容的話,繼續(xù)匹配yes部分的表達(dá)式,否則繼續(xù)匹配no部分
-
(?!) 零寬負(fù)向先行斷言,由于沒有后綴表達(dá)式,試圖匹配總是失敗
如果你不是一個(gè)程序員(或者你自稱程序員但是不知道堆棧是什么東西),你就這樣理解上面的三種語(yǔ)法吧:第一個(gè)就是在黑板上寫一個(gè)"group",第二個(gè)就是從黑板上擦掉一個(gè)"group",第三個(gè)就是看黑板上寫的還有沒有"group",如果有就繼續(xù)匹配yes部分,否則就匹配no部分。
我們需要做的是每碰到了左括號(hào),就在壓入一個(gè)"Open",每碰到一個(gè)右括號(hào),就彈出一個(gè),到了最后就看看堆棧是否為空--如果不為空那就證明左括號(hào)比右括號(hào)多,那匹配就應(yīng)該失敗。正則表達(dá)式引擎會(huì)進(jìn)行回溯(放棄最前面或最后面的一些字符),盡量使整個(gè)表達(dá)式得到匹配。
< #最外層的左括號(hào)
[^<>]* #最外層的左括號(hào)后面的不是括號(hào)的內(nèi)容
(
(
(?'Open'<) #碰到了左括號(hào),在黑板上寫一個(gè)"Open"
[^<>]* #匹配左括號(hào)后面的不是括號(hào)的內(nèi)容
)+
(
(?'-Open'>) #碰到了右括號(hào),擦掉一個(gè)"Open"
[^<>]* #匹配右括號(hào)后面不是括號(hào)的內(nèi)容
)+
)*
(?(Open)(?!)) #在遇到最外層的右括號(hào)前面,判斷黑板上還有沒有沒擦掉的"Open";如果還有,則匹配失敗
> #最外層的右括號(hào)
平衡組的一個(gè)最常見的應(yīng)用就是匹配HTML,下面這個(gè)例子可以匹配嵌套的<div>標(biāo)簽:<div[^>]*>[^<>]*(((?'Open'<div[^>]*>)[^<>]*)+((?'-Open'</div>)[^<>]*)+)*(?(Open)(?!))</div>.
還有些什么東西沒提到
我已經(jīng)描述了構(gòu)造正則表達(dá)式的大量元素,還有一些我沒有提到的東西。下面是未提到的元素的列表,包含語(yǔ)法和簡(jiǎn)單的說(shuō)明。你可以在網(wǎng)上找到更詳細(xì)的參考資料來(lái)學(xué)習(xí)它們--當(dāng)你需要用到它們的時(shí)候。如果你安裝了MSDN Library,你也可以在里面找到關(guān)于.net下正則表達(dá)式詳細(xì)的文檔。
表7.尚未詳細(xì)討論的語(yǔ)法
代碼/語(yǔ)法 |
說(shuō)明 |
\a
|
報(bào)警字符(打印它的效果是電腦嘀一聲)
|
\b
|
通常是單詞分界位置,但如果在字符類里使用代表退格
|
\t
|
制表符,Tab
|
\r
|
回車
|
\v
|
豎向制表符
|
\f
|
換頁(yè)符
|
\n
|
換行符
|
\e
|
Escape
|
\0nn
|
ASCII代碼中八進(jìn)制代碼為nn的字符
|
\xnn
|
ASCII代碼中十六進(jìn)制代碼為nn的字符
|
\unnnn
|
Unicode代碼中十六進(jìn)制代碼為nnnn的字符
|
\cN
|
ASCII控制字符。比如\cC代表Ctrl+C
|
\A
|
字符串開頭(類似^,但不受處理多行選項(xiàng)的影響)
|
\Z
|
字符串結(jié)尾或行尾(不受處理多行選項(xiàng)的影響)
|
\z
|
字符串結(jié)尾(類似$,但不受處理多行選項(xiàng)的影響)
|
\G
|
當(dāng)前搜索的開頭
|
\p{name}
|
Unicode中命名為name的字符類,例如\p{IsGreek}
|
(?>exp)
|
貪婪子表達(dá)式
|
(?<x>-<y>exp)
|
平衡組
|
(?im-nsx:exp)
|
在子表達(dá)式exp中改變處理選項(xiàng)
|
(?im-nsx)
|
為表達(dá)式后面的部分改變處理選項(xiàng)
|
(?(exp)yes|no)
|
把exp當(dāng)作零寬正向先行斷言,如果在這個(gè)位置能匹配,使用yes作為此組的表達(dá)式;否則使用no
|
(?(exp)yes)
|
同上,只是使用空表達(dá)式作為no
|
(?(name)yes|no)
|
如果命名為name的組捕獲到了內(nèi)容,使用yes作為表達(dá)式;否則使用no
|
(?(name)yes)
|
同上,只是使用空表達(dá)式作為no
|
posted @
2008-10-17 14:13 華夢(mèng)行 閱讀(1013) |
評(píng)論 (0) |
編輯 收藏
posted @
2008-10-17 13:53 華夢(mèng)行 閱讀(778) |
評(píng)論 (1) |
編輯 收藏
?由于常常要和漢字處理打交道,因此,我常常受到漢字編碼問題的困擾。在不斷的打擊與堅(jiān)持中,也積累了一點(diǎn)漢字編碼方面的經(jīng)驗(yàn),想和大家一起分享。
一、漢字編碼的種類
???
漢字編碼中現(xiàn)在主要用到的有三類,包括GBK,GB2312和Big5。
??? 1
、GB2312又稱國(guó)標(biāo)碼,
由國(guó)家標(biāo)準(zhǔn)總局發(fā)布,
1981
年
5
月
1
日實(shí)施,通行于大陸。新加坡等地也使用此編碼。它是一個(gè)簡(jiǎn)化字的編碼規(guī)范,當(dāng)然也包括其他的符號(hào)、字母、日文假名等,共
7445
個(gè)圖形字符,其中漢字占
6763
個(gè)。我們平時(shí)說(shuō)
6768
個(gè)漢字,實(shí)際上里邊有
5
個(gè)編碼為空白,所以總共有
6763
個(gè)漢字。
? ??? GB2312
規(guī)定“對(duì)任意一個(gè)圖形字符都采用兩個(gè)字節(jié)表示,每個(gè)字節(jié)均采用七位編碼表示”,習(xí)慣上稱第一個(gè)字節(jié)為“高字節(jié)”,第二個(gè)字節(jié)為“低字節(jié)”。
GB2312
中漢字的編碼范圍為,第一字節(jié)0xB0-0xF7(對(duì)應(yīng)十進(jìn)制為176-247),第二個(gè)字節(jié)0xA0-0xFE(對(duì)應(yīng)十進(jìn)制為160-254)。
???
GB2312
將代碼表分為
94
個(gè)區(qū),對(duì)應(yīng)第一字節(jié)(
0xa1-0xfe
);每個(gè)區(qū)
94
個(gè)位(
0xa1-0xfe
),對(duì)應(yīng)第二字節(jié),兩個(gè)字節(jié)的值分別為區(qū)號(hào)值和位號(hào)值加
32
(
2OH
),因此也稱為區(qū)位碼。
01-09
區(qū)為符號(hào)、數(shù)字區(qū),
16-87
區(qū)為漢字區(qū)(
0xb0-0xf7
),
10-15
區(qū)、
88-94
區(qū)是有待進(jìn)一步標(biāo)準(zhǔn)化的空白區(qū)。
?
?????? 2
、
Big5
又稱大五碼,主要為香港與臺(tái)灣使用,即是一個(gè)繁體字編碼。
每個(gè)漢字由兩個(gè)字節(jié)構(gòu)成,第一個(gè)字節(jié)的范圍從
0X81
-
0XFE
(即
129-255
),共
126
種。第二個(gè)字節(jié)的范圍不連續(xù),分別為
0X40
-
0X7E
(即
64-126
),
0XA1
-
0XFE
(即
161-254
),共
157
種。
?
??? 3
、GBK是GB2312的擴(kuò)展,是向上兼容的,因此GB2312中的漢字的編碼與GBK中漢字的相同。另外,GBK中還包含繁體字的編碼,它與Big5編碼之間的關(guān)系我還沒有弄明白,好像是不一致的。GBK中每個(gè)漢字仍然包含兩個(gè)字節(jié),第一個(gè)字節(jié)的范圍是0x81-0xFE(即129-254),第二個(gè)字節(jié)的范圍是0x40-0xFE(即64-254)。GBK中有碼位23940個(gè),包含漢字21003個(gè)。
????????????????????????????????????
??????????????????????????????????
表1 漢字編碼范圍
名稱
|
第一字節(jié)
|
第二字節(jié)
|
GB2312
|
0xB0-0xF7(176-247)
|
0xA0-0xFE
(
160-254
)
|
GBK
|
0x81-0xFE
(
129-254
)
|
0x40-0xFE
(
64-254
)
|
Big5
|
0x81-0xFE
(
129-255
)
|
0x40-0x7E
(
64-126
)
0xA1
-
0xFE
(
161-254
)
|
?
?
二、對(duì)漢字進(jìn)行hash
???
為了處理漢字的方便,在查找漢字的時(shí)候,我們通常會(huì)用到hash的方法,那怎么來(lái)確定一個(gè)漢字位置呢?這就和每種編碼的排列有關(guān)了,這里主要給出一種hash函數(shù)的策略。
???
對(duì)于GB2312編碼,設(shè)輸入的漢字為GBword,我們可以采用公式(C1-176)*94 + (C2-161)確定GBindex。其中,C1表示第一字節(jié),C2表示第二字節(jié)。具體如下:
??? GBindex = ((unsigned char)GBword.at(0)-176)*94 + (unsigned char)GBword.at(1) - 161;
???
之所以用unsigned char類型,是因?yàn)?span lang="EN-US">char是一個(gè)字節(jié),如果用unsigend int,因?yàn)?span lang="EN-US">int是4個(gè)字節(jié)的,所以會(huì)造成擴(kuò)展,導(dǎo)致錯(cuò)誤。
??????
對(duì)于GBK編碼,設(shè)輸入的漢字為GBKword,則可以采用公式??
index=(ch1-0x81)*190+(ch2-0x40)-(ch2/128)
,其中ch1是第一字節(jié),ch2是第二字節(jié)。
???
具體的,
??? GBKindex = ((unsigned char)GBKword[0]-129)*190 +
??????? ?????? ((unsigned char)GBKword[1]-64) - (unsigned char)GBKword[1]/128;
?
三、怎樣判斷一個(gè)漢字的是什么編碼
直接根據(jù)漢字的編碼范圍判斷,對(duì)于GB2312和GBK可用下面兩個(gè)程序?qū)崿F(xiàn)。
1
、判斷是否是GB2312
bool isGBCode(const string& strIn)
{
??? unsigned char ch1;
??? unsigned char ch2;
???
??? if (strIn.size() >= 2)
??? {
??????? ch1 = (unsigned char)strIn.at(0);
??????? ch2 = (unsigned char)strIn.at(1);
??????? if (ch1>=176 && ch1<=247 && ch2>=160 && ch2<=254)
??????????? return true;
??????? else return false;
??? }
??? else return false;
}
2
、判斷是否是GBK編碼
bool isGBKCode(const string& strIn)
{
??? unsigned char ch1;
??? unsigned char ch2;
???
???
if (strIn.size() >= 2)
??? {
???????
ch1 = (unsigned char)strIn.at(0);
??????? ch2 = (unsigned char)strIn.at(1);
??????? if (ch1>=129 && ch1<=254 && ch2>=64 && ch2<=254)
??????????? return true;
??????? else return false;
??? }
??? else return false;
}
?
3
、對(duì)于Big5
??? 它的范圍為:高字節(jié)從0xA0到0xFE,低字節(jié)從0x40到0x7E,和0xA1到0xFE兩部分。判斷一個(gè)漢字是否是BIG5編碼,可以如上對(duì)字符的編碼范圍判斷即可。如何定位呢?那么也想象所有編碼排列為一個(gè)二維坐標(biāo),縱坐標(biāo)是高字節(jié),橫坐標(biāo)是低字節(jié)。這樣一行上的漢字個(gè)數(shù):(0x7E-0x40+1)+(0xFE-0xA1+1)=157。那么定位算法分兩塊,為: ?
??? if 0x40<=ch2<=0x7E: #is big5 char
??? index=((ch1-0xA1)*157+(ch2-0x40))*2
??? elif 0xA1<=ch2<=0xFE: #is big5 char
??? index=((ch1-0xA1)*157+(ch2-0xA1+63))*2
?
對(duì)于第二塊,計(jì)算偏移量時(shí)因?yàn)橛袃蓧K數(shù)值,所以在計(jì)算后面一段值時(shí),不要忘了前面還有一段值。0x7E-0x40+1=63。
?
四、如果判斷一個(gè)字符是西文字符還是中文字符
???
大家知道西文字符主要是指
ASCII
碼,它用一個(gè)字節(jié)表示。且這個(gè)字符轉(zhuǎn)換成數(shù)字之后,該數(shù)字是大于0的,而漢字是兩個(gè)字節(jié)的,第一個(gè)字節(jié)的轉(zhuǎn)化為數(shù)字之后應(yīng)該是小于0的,因此可以根據(jù)每個(gè)字節(jié)轉(zhuǎn)化為數(shù)字之后是否小于0,判斷它是否是漢字。
???
例如,設(shè)輸入字為strin,則,
???? If (strin.at(0) < 0)
?????? cout << ”
是漢字” << endl;
???? else cout << ”
不是漢字” << endl;
五、編碼表下載
?? GBK編碼表,下載
?? GB2312編碼表,下載
posted @
2008-10-16 10:36 華夢(mèng)行 閱讀(287) |
評(píng)論 (0) |
編輯 收藏
下面都是我收集的一些比較常用的正則表達(dá)式,因?yàn)槠匠?赡茉诒韱悟?yàn)證的時(shí)候,用到的比較多。特發(fā)出來(lái),讓各位朋友共同使用。呵呵。
匹配中文字符的正則表達(dá)式: [u4e00-u9fa5]
評(píng)注:匹配中文還真是個(gè)頭疼的事,有了這個(gè)表達(dá)式就好辦了
匹配雙字節(jié)字符(包括漢字在內(nèi)):[^x00-xff]
評(píng)注:可以用來(lái)計(jì)算字符串的長(zhǎng)度(一個(gè)雙字節(jié)字符長(zhǎng)度計(jì)2,ASCII字符計(jì)1)
匹配空白行的正則表達(dá)式:ns*r
評(píng)注:可以用來(lái)刪除空白行
匹配HTML標(biāo)記的正則表達(dá)式:< (S*?)[^>]*>.*?|< .*? />
評(píng)注:網(wǎng)上流傳的版本太糟糕,上面這個(gè)也僅僅能匹配部分,對(duì)于復(fù)雜的嵌套標(biāo)記依舊無(wú)能為力
匹配首尾空白字符的正則表達(dá)式:^s*|s*$
評(píng)注:可以用來(lái)刪除行首行尾的空白字符(包括空格、制表符、換頁(yè)符等等),非常有用的表達(dá)式
匹配Email地址的正則表達(dá)式:w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*
評(píng)注:表單驗(yàn)證時(shí)很實(shí)用
匹配網(wǎng)址URL的正則表達(dá)式:[a-zA-z]+://[^s]*
評(píng)注:網(wǎng)上流傳的版本功能很有限,上面這個(gè)基本可以滿足需求
匹配帳號(hào)是否合法(字母開頭,允許5-16字節(jié),允許字母數(shù)字下劃線):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
評(píng)注:表單驗(yàn)證時(shí)很實(shí)用
匹配國(guó)內(nèi)電話號(hào)碼:d{3}-d{8}|d{4}-d{7}
評(píng)注:匹配形式如 0511-4405222 或 021-87888822
匹配騰訊QQ號(hào):[1-9][0-9]{4,}
評(píng)注:騰訊QQ號(hào)從10000開始
匹配中國(guó)郵政編碼:[1-9]d{5}(?!d)
評(píng)注:中國(guó)郵政編碼為6位數(shù)字
匹配身份證:d{15}|d{18}
評(píng)注:中國(guó)的身份證為15位或18位
匹配ip地址:d+.d+.d+.d+
評(píng)注:提取ip地址時(shí)有用
匹配特定數(shù)字:
^[1-9]d*$ //匹配正整數(shù)
^-[1-9]d*$ //匹配負(fù)整數(shù)
^-?[1-9]d*$ //匹配整數(shù)
^[1-9]d*|0$ //匹配非負(fù)整數(shù)(正整數(shù) + 0)
^-[1-9]d*|0$ //匹配非正整數(shù)(負(fù)整數(shù) + 0)
^[1-9]d*.d*|0.d*[1-9]d*$ //匹配正浮點(diǎn)數(shù)
^-([1-9]d*.d*|0.d*[1-9]d*)$ //匹配負(fù)浮點(diǎn)數(shù)
^-?([1-9]d*.d*|0.d*[1-9]d*|0?.0+|0)$ //匹配浮點(diǎn)數(shù)
^[1-9]d*.d*|0.d*[1-9]d*|0?.0+|0$ //匹配非負(fù)浮點(diǎn)數(shù)(正浮點(diǎn)數(shù) + 0)
^(-([1-9]d*.d*|0.d*[1-9]d*))|0?.0+|0$ //匹配非正浮點(diǎn)數(shù)(負(fù)浮點(diǎn)數(shù) + 0)
評(píng)注:處理大量數(shù)據(jù)時(shí)有用,具體應(yīng)用時(shí)注意修正
匹配特定字符串:
^[A-Za-z]+$ //匹配由26個(gè)英文字母組成的字符串
^[A-Z]+$ //匹配由26個(gè)英文字母的大寫組成的字符串
^[a-z]+$ //匹配由26個(gè)英文字母的小寫組成的字符串
^[A-Za-z0-9]+$ //匹配由數(shù)字和26個(gè)英文字母組成的字符串
^w+$ //匹配由數(shù)字、26個(gè)英文字母或者下劃線組成的字符串
在使用RegularExpressionValidator驗(yàn)證控件時(shí)的驗(yàn)證功能及其驗(yàn)證表達(dá)式介紹如下:
只能輸入數(shù)字:“^[0-9]*$”
只能輸入n位的數(shù)字:“^d{n}$”
只能輸入至少n位數(shù)字:“^d{n,}$”
只能輸入m-n位的數(shù)字:“^d{m,n}$”
只能輸入零和非零開頭的數(shù)字:“^(0|[1-9][0-9]*)$”
只能輸入有兩位小數(shù)的正實(shí)數(shù):“^[0-9]+(.[0-9]{2})?$”
只能輸入有1-3位小數(shù)的正實(shí)數(shù):“^[0-9]+(.[0-9]{1,3})?$”
只能輸入非零的正整數(shù):“^+?[1-9][0-9]*$”
只能輸入非零的負(fù)整數(shù):“^-[1-9][0-9]*$”
只能輸入長(zhǎng)度為3的字符:“^.{3}$”
只能輸入由26個(gè)英文字母組成的字符串:“^[A-Za-z]+$”
只能輸入由26個(gè)大寫英文字母組成的字符串:“^[A-Z]+$”
只能輸入由26個(gè)小寫英文字母組成的字符串:“^[a-z]+$”
只能輸入由數(shù)字和26個(gè)英文字母組成的字符串:“^[A-Za-z0-9]+$”
只能輸入由數(shù)字、26個(gè)英文字母或者下劃線組成的字符串:“^w+$”
驗(yàn)證用戶密碼:“^[a-zA-Z]w{5,17}$”正確格式為:以字母開頭,長(zhǎng)度在6-18之間,
只能包含字符、數(shù)字和下劃線。
驗(yàn)證是否含有^%&’,;=?$”等字符:“[^%&',;=?$x22]+”
只能輸入漢字:“^[u4e00-u9fa5],{0,}$”
驗(yàn)證Email地址:“^w+[-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*$”
驗(yàn)證InternetURL:“^http://([w-]+.)+[w-]+(/[w-./?%&=]*)?$”
驗(yàn)證電話號(hào)碼:“^((d{3,4})|d{3,4}-)?d{7,8}$”
正確格式為:“XXXX-XXXXXXX”,“XXXX-XXXXXXXX”,“XXX-XXXXXXX”,
“XXX-XXXXXXXX”,“XXXXXXX”,“XXXXXXXX”。
驗(yàn)證身份證號(hào)(15位或18位數(shù)字):“^d{15}|d{}18$”
驗(yàn)證一年的12個(gè)月:“^(0?[1-9]|1[0-2])$”正確格式為:“01”-“09”和“1”“12”
驗(yàn)證一個(gè)月的31天:“^((0?[1-9])|((1|2)[0-9])|30|31)$”
正確格式為:“01”“09”和“1”“31”。
匹配中文字符的正則表達(dá)式: [u4e00-u9fa5]
匹配雙字節(jié)字符(包括漢字在內(nèi)):[^x00-xff]
匹配空行的正則表達(dá)式:n[s| ]*r
匹配HTML標(biāo)記的正則表達(dá)式:/< (.*)>.*|< (.*) />/
匹配首尾空格的正則表達(dá)式:(^s*)|(s*$)
匹配Email地址的正則表達(dá)式:w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*
匹配網(wǎng)址URL的正則表達(dá)式:http://([w-]+.)+[w-]+(/[w- ./?%&=]*)?
(1)應(yīng)用:計(jì)算字符串的長(zhǎng)度(一個(gè)雙字節(jié)字符長(zhǎng)度計(jì)2,ASCII字符計(jì)1)
String.prototype.len=function(){return this.replace([^x00-xff]/g,”aa”).length;}
(2)應(yīng)用:javascript中沒有像vbscript那樣的trim函數(shù),我們就可以利用這個(gè)表達(dá)式來(lái)實(shí)現(xiàn)
String.prototype.trim = function()
{
return this.replace(/(^s*)|(s*$)/g, “”);
}
(3)應(yīng)用:利用正則表達(dá)式分解和轉(zhuǎn)換IP地址
function IP2V(ip) //IP地址轉(zhuǎn)換成對(duì)應(yīng)數(shù)值
{
re=/(d+).(d+).(d+).(d+)/g //匹配IP地址的正則表達(dá)式
if(re.test(ip))
{
return RegExp.$1*Math.pow(255,3))+RegExp.$2*Math.pow(255,2))+RegExp.$3*255+RegExp.$4*1
}
else
{
throw new Error(”Not a valid IP address!”)
}
}
(4)應(yīng)用:從URL地址中提取文件名的javascript程序
s=”http://www.9499.net/page1.htm”;
s=s.replace(/(.*/){0,}([^.]+).*/ig,”$2″) ; //Page1.htm
(5)應(yīng)用:利用正則表達(dá)式限制網(wǎng)頁(yè)表單里的文本框輸入內(nèi)容
用正則表達(dá)式限制只能輸入中文:onkeyup=”value=”/blog/value.replace(/["^u4E00-u9FA5]/g,”) ” onbeforepaste=”clipboardData.setData(’text’,clipboardData.getData(’text’).replace(/[^u4E00-u9FA5]/g,”))”
用正則表達(dá)式限制只能輸入全角字符: onkeyup=”value=”/blog/value.replace(/["^uFF00-uFFFF]/g,”) ” onbeforepaste=”clipboardData.setData(’text’,clipboardData.getData(’text’).replace(/[^uFF00-uFFFF]/g,”))”
用正則表達(dá)式限制只能輸入數(shù)字:onkeyup=”value=”/blog/value.replace(/["^d]/g,”) “onbeforepaste= “clipboardData.setData(’text’,clipboardData.getData(’text’).replace(/[^d]/g,”))”
用正則表達(dá)式限制只能輸入數(shù)字和英文:onkeyup=”value=”/blog/value.replace(/[W]/g,””) “onbeforepaste=”clipboardData.setData(’text’,clipboardData.getData(’text’).replace(/[^d]/g,”
posted @
2008-10-16 10:34 華夢(mèng)行 閱讀(249) |
評(píng)論 (0) |
編輯 收藏
?由于常常要和漢字處理打交道,因此,我常常受到漢字編碼問題的困擾。在不斷的打擊與堅(jiān)持中,也積累了一點(diǎn)漢字編碼方面的經(jīng)驗(yàn),想和大家一起分享。
一、漢字編碼的種類
???
漢字編碼中現(xiàn)在主要用到的有三類,包括GBK,GB2312和Big5。
??? 1
、GB2312又稱國(guó)標(biāo)碼,
由國(guó)家標(biāo)準(zhǔn)總局發(fā)布,
1981
年
5
月
1
日實(shí)施,通行于大陸。新加坡等地也使用此編碼。它是一個(gè)簡(jiǎn)化字的編碼規(guī)范,當(dāng)然也包括其他的符號(hào)、字母、日文假名等,共
7445
個(gè)圖形字符,其中漢字占
6763
個(gè)。我們平時(shí)說(shuō)
6768
個(gè)漢字,實(shí)際上里邊有
5
個(gè)編碼為空白,所以總共有
6763
個(gè)漢字。
? ??? GB2312
規(guī)定“對(duì)任意一個(gè)圖形字符都采用兩個(gè)字節(jié)表示,每個(gè)字節(jié)均采用七位編碼表示”,習(xí)慣上稱第一個(gè)字節(jié)為“高字節(jié)”,第二個(gè)字節(jié)為“低字節(jié)”。
GB2312
中漢字的編碼范圍為,第一字節(jié)0xB0-0xF7(對(duì)應(yīng)十進(jìn)制為176-247),第二個(gè)字節(jié)0xA0-0xFE(對(duì)應(yīng)十進(jìn)制為160-254)。
???
GB2312
將代碼表分為
94
個(gè)區(qū),對(duì)應(yīng)第一字節(jié)(
0xa1-0xfe
);每個(gè)區(qū)
94
個(gè)位(
0xa1-0xfe
),對(duì)應(yīng)第二字節(jié),兩個(gè)字節(jié)的值分別為區(qū)號(hào)值和位號(hào)值加
32
(
2OH
),因此也稱為區(qū)位碼。
01-09
區(qū)為符號(hào)、數(shù)字區(qū),
16-87
區(qū)為漢字區(qū)(
0xb0-0xf7
),
10-15
區(qū)、
88-94
區(qū)是有待進(jìn)一步標(biāo)準(zhǔn)化的空白區(qū)。
?
?????? 2
、
Big5
又稱大五碼,主要為香港與臺(tái)灣使用,即是一個(gè)繁體字編碼。
每個(gè)漢字由兩個(gè)字節(jié)構(gòu)成,第一個(gè)字節(jié)的范圍從
0X81
-
0XFE
(即
129-255
),共
126
種。第二個(gè)字節(jié)的范圍不連續(xù),分別為
0X40
-
0X7E
(即
64-126
),
0XA1
-
0XFE
(即
161-254
),共
157
種。
?
??? 3
、GBK是GB2312的擴(kuò)展,是向上兼容的,因此GB2312中的漢字的編碼與GBK中漢字的相同。另外,GBK中還包含繁體字的編碼,它與Big5編碼之間的關(guān)系我還沒有弄明白,好像是不一致的。GBK中每個(gè)漢字仍然包含兩個(gè)字節(jié),第一個(gè)字節(jié)的范圍是0x81-0xFE(即129-254),第二個(gè)字節(jié)的范圍是0x40-0xFE(即64-254)。GBK中有碼位23940個(gè),包含漢字21003個(gè)。
????????????????????????????????????
??????????????????????????????????
表1 漢字編碼范圍
名稱
|
第一字節(jié)
|
第二字節(jié)
|
GB2312
|
0xB0-0xF7(176-247)
|
0xA0-0xFE
(
160-254
)
|
GBK
|
0x81-0xFE
(
129-254
)
|
0x40-0xFE
(
64-254
)
|
Big5
|
0x81-0xFE
(
129-255
)
|
0x40-0x7E
(
64-126
)
0xA1
-
0xFE
(
161-254
)
|
?
?
二、對(duì)漢字進(jìn)行hash
???
為了處理漢字的方便,在查找漢字的時(shí)候,我們通常會(huì)用到hash的方法,那怎么來(lái)確定一個(gè)漢字位置呢?這就和每種編碼的排列有關(guān)了,這里主要給出一種hash函數(shù)的策略。
???
對(duì)于GB2312編碼,設(shè)輸入的漢字為GBword,我們可以采用公式(C1-176)*94 + (C2-161)確定GBindex。其中,C1表示第一字節(jié),C2表示第二字節(jié)。具體如下:
??? GBindex = ((unsigned char)GBword.at(0)-176)*94 + (unsigned char)GBword.at(1) - 161;
???
之所以用unsigned char類型,是因?yàn)?span lang="EN-US">char是一個(gè)字節(jié),如果用unsigend int,因?yàn)?span lang="EN-US">int是4個(gè)字節(jié)的,所以會(huì)造成擴(kuò)展,導(dǎo)致錯(cuò)誤。
??????
對(duì)于GBK編碼,設(shè)輸入的漢字為GBKword,則可以采用公式??
index=(ch1-0x81)*190+(ch2-0x40)-(ch2/128)
,其中ch1是第一字節(jié),ch2是第二字節(jié)。
???
具體的,
??? GBKindex = ((unsigned char)GBKword[0]-129)*190 +
??????? ?????? ((unsigned char)GBKword[1]-64) - (unsigned char)GBKword[1]/128;
?
三、怎樣判斷一個(gè)漢字的是什么編碼
直接根據(jù)漢字的編碼范圍判斷,對(duì)于GB2312和GBK可用下面兩個(gè)程序?qū)崿F(xiàn)。
1
、判斷是否是GB2312
bool isGBCode(const string& strIn)
{
??? unsigned char ch1;
??? unsigned char ch2;
???
??? if (strIn.size() >= 2)
??? {
??????? ch1 = (unsigned char)strIn.at(0);
??????? ch2 = (unsigned char)strIn.at(1);
??????? if (ch1>=176 && ch1<=247 && ch2>=160 && ch2<=254)
??????????? return true;
??????? else return false;
??? }
??? else return false;
}
2
、判斷是否是GBK編碼
bool isGBKCode(const string& strIn)
{
??? unsigned char ch1;
??? unsigned char ch2;
???
???
if (strIn.size() >= 2)
??? {
???????
ch1 = (unsigned char)strIn.at(0);
??????? ch2 = (unsigned char)strIn.at(1);
??????? if (ch1>=129 && ch1<=254 && ch2>=64 && ch2<=254)
??????????? return true;
??????? else return false;
??? }
??? else return false;
}
?
3
、對(duì)于Big5
??? 它的范圍為:高字節(jié)從0xA0到0xFE,低字節(jié)從0x40到0x7E,和0xA1到0xFE兩部分。判斷一個(gè)漢字是否是BIG5編碼,可以如上對(duì)字符的編碼范圍判斷即可。如何定位呢?那么也想象所有編碼排列為一個(gè)二維坐標(biāo),縱坐標(biāo)是高字節(jié),橫坐標(biāo)是低字節(jié)。這樣一行上的漢字個(gè)數(shù):(0x7E-0x40+1)+(0xFE-0xA1+1)=157。那么定位算法分兩塊,為: ?
??? if 0x40<=ch2<=0x7E: #is big5 char
??? index=((ch1-0xA1)*157+(ch2-0x40))*2
??? elif 0xA1<=ch2<=0xFE: #is big5 char
??? index=((ch1-0xA1)*157+(ch2-0xA1+63))*2
?
對(duì)于第二塊,計(jì)算偏移量時(shí)因?yàn)橛袃蓧K數(shù)值,所以在計(jì)算后面一段值時(shí),不要忘了前面還有一段值。0x7E-0x40+1=63。
?
四、如果判斷一個(gè)字符是西文字符還是中文字符
???
大家知道西文字符主要是指
ASCII
碼,它用一個(gè)字節(jié)表示。且這個(gè)字符轉(zhuǎn)換成數(shù)字之后,該數(shù)字是大于0的,而漢字是兩個(gè)字節(jié)的,第一個(gè)字節(jié)的轉(zhuǎn)化為數(shù)字之后應(yīng)該是小于0的,因此可以根據(jù)每個(gè)字節(jié)轉(zhuǎn)化為數(shù)字之后是否小于0,判斷它是否是漢字。
???
例如,設(shè)輸入字為strin,則,
???? If (strin.at(0) < 0)
?????? cout << ”
是漢字” << endl;
???? else cout << ”
不是漢字” << endl;
漢字在 Unicode 里面有單獨(dú)的幾塊區(qū)域,是中日韓(朝鮮)共享的。
以下兩段
U+4e00 ~ U+9FB0 原來(lái) GB2312 和 GBK 中的漢字
U+3400 ~ U+4DB6 包括 GB18030.2000 中那些增加的漢字
五、編碼表下載
?? GBK編碼表,下載
?? GB2312編碼表,下載
posted @
2008-10-16 10:03 華夢(mèng)行 閱讀(300) |
評(píng)論 (0) |
編輯 收藏
這一段出現(xiàn)了亂碼,那么不妨用窮舉法猜測(cè)一下它的實(shí)際編碼格式。
System.out.println(new String(testString.getBytes("ISO-8859-1"),"gb2312"));
System.out.println(new String(testString.getBytes("UTF8"),"gb2312"));
System.out.println(new String(testString.getBytes("GB2312"),"gb2312"));
System.out.println(new String(testString.getBytes("GBK"),"gb2312"));
System.out.println(new String(testString.getBytes("BIG5"),"gb2312"));
posted @
2008-10-16 09:57 華夢(mèng)行 閱讀(265) |
評(píng)論 (0) |
編輯 收藏
Unicode字符編碼規(guī)范
Unicode是一種字符編碼規(guī)范 。
先從ASCII說(shuō)起。ASCII是用來(lái)表示英文字符的一種編碼規(guī)范,每個(gè)ASCII字符占用1個(gè)字節(jié)(8bits)
因此,ASCII編碼可以表示的最大字符數(shù)是256,其實(shí)英文字符并沒有那么多,一般只用前128個(gè)(最高位為0),其中包括了控制字符、數(shù)字、大小寫字母和其他一些符號(hào)
。
而最高位為1的另128個(gè)字符被成為“擴(kuò)展ASCII”,一般用來(lái)存放英文的制表符、部分音標(biāo)字符等等的一些其他符號(hào)
這種字符編碼規(guī)范顯然用來(lái)處理英文沒有什么問題
。(實(shí)際上也可以用來(lái)處理法文、德文等一些其他的西歐字符,但是不能和英文通用),但是面對(duì)中文、阿拉伯文之類復(fù)雜的文字,255個(gè)字符顯然不夠用
于是,各個(gè)國(guó)家紛紛制定了自己的文字編碼規(guī)范,其中中文的文字編碼規(guī)范叫做“GB2312-80”,它是和ASCII兼容的一種編碼規(guī)范,其實(shí)就是利用擴(kuò)展ASCII沒有真正標(biāo)準(zhǔn)化這一點(diǎn),把一個(gè)中文字符用兩個(gè)擴(kuò)展ASCII字符來(lái)表示。
但 是這個(gè)方法有問題,最大的問題就是,中文文字沒有真正屬于自己的編碼,因?yàn)閿U(kuò)展ASCII碼雖然沒有真正的標(biāo)準(zhǔn)化,但是PC里的ASCII碼還是有一個(gè)事 實(shí)標(biāo)準(zhǔn)的(存放著英文制表符),所以很多軟件利用這些符號(hào)來(lái)畫表格。這樣的軟件用到中文系統(tǒng)中,這些表格符就會(huì)被誤認(rèn)作中文字,破壞版面。而且,統(tǒng)計(jì)中英 文混合字符串中的字?jǐn)?shù),也是比較復(fù)雜的,我們必須判斷一個(gè)ASCII碼是否擴(kuò)展,以及它的下一個(gè)ASCII是否擴(kuò)展,然后才“猜”那可能是一個(gè)中文字
。
總之當(dāng)時(shí)處理中文是很痛苦的。而更痛苦的是GB2312是國(guó)家標(biāo)準(zhǔn),臺(tái)灣當(dāng)時(shí)有一個(gè)Big5編碼標(biāo)準(zhǔn),很多編碼和GB是相同的,所以……,嘿嘿。
這 時(shí)候,我們就知道,要真正解決中文問題,不能從擴(kuò)展ASCII的角度入手,也不能僅靠中國(guó)一家來(lái)解決。而必須有一個(gè)全新的編碼系統(tǒng),這個(gè)系統(tǒng)要可以將中 文、英文、法文、德文……等等所有的文字統(tǒng)一起來(lái)考慮,為每個(gè)文字都分配一個(gè)單獨(dú)的編碼,這樣才不會(huì)有上面那種現(xiàn)象出現(xiàn)。
于是,Unicode誕生了。
Unicode有兩套標(biāo)準(zhǔn),一套叫UCS-2(Unicode-16),用2個(gè)字節(jié)為字符編碼,另一套叫UCS-4(Unicode-32),用4個(gè)字節(jié)為字符編碼。
以目前常用的UCS-2為例,它可以表示的字符數(shù)為2^16=65535,基本上可以容納所有的歐美字符和絕大部分的亞洲字符
。
UTF-8的問題后面會(huì)提到 。
在Unicode里,所有的字符被一視同仁。漢字不再使用“兩個(gè)擴(kuò)展ASCII”,而是使用“1個(gè)Unicode”,注意,現(xiàn)在的漢字是“一個(gè)字符”了,于是,拆字、統(tǒng)計(jì)字?jǐn)?shù)這些問題也就自然而然的解決了
。
但是,這個(gè)世界不是理想的,不可能在一夜之間所有的系統(tǒng)都使用Unicode來(lái)處理字符,所以Unicode在誕生之日,就必須考慮一個(gè)嚴(yán)峻的問題:和ASCII字符集之間的不兼容問題。
我們知道,ASCII字符是單個(gè)字節(jié)的,比如“A”的ASCII是65。而Unicode是雙字節(jié)的,比如“A”的Unicode是0065,這就造成了一個(gè)非常大的問題:以前處理ASCII的那套機(jī)制不能被用來(lái)處理Unicode了
。
另一個(gè)更加嚴(yán)重的問題是,C語(yǔ)言使用’\0′作為字符串結(jié)尾,而Unicode里恰恰有很多字符都有一個(gè)字節(jié)為0,這樣一來(lái),C語(yǔ)言的字符串函數(shù)將無(wú)法正常處理Unicode,除非把世界上所有用C寫的程序以及他們所用的函數(shù)庫(kù)全部換掉
。
于是,比Unicode更偉大的東東誕生了,之所以說(shuō)它更偉大是因?yàn)樗孶nicode不再存在于紙上,而是真實(shí)的存在于我們大家的電腦中。那就是:UTF
。
UTF= UCS Transformation Format UCS轉(zhuǎn)換格式
它是將Unicode編碼規(guī)則和計(jì)算機(jī)的實(shí)際編碼對(duì)應(yīng)起來(lái)的一個(gè)規(guī)則。現(xiàn)在流行的UTF有2種:UTF-8和UTF-16
。
其中UTF-16和上面提到的Unicode本身的編碼規(guī)范是一致的,這里不多說(shuō)了。而UTF-8不同,它定義了一種“區(qū)間規(guī)則”,這種規(guī)則可以和ASCII編碼保持最大程度的兼容
。
UTF-8有點(diǎn)類似于Haffman編碼,它將Unicode編碼為00000000-0000007F的字符,用單個(gè)字節(jié)來(lái)表示;
00000080-000007FF的字符用兩個(gè)字節(jié)表示
00000800-0000FFFF的字符用3字節(jié)表示
因?yàn)槟壳盀橹筓nicode-16規(guī)范沒有指定FFFF以上的字符,所以UTF-8最多是使用3個(gè)字節(jié)來(lái)表示一個(gè)字符。但理論上來(lái)說(shuō),UTF-8最多需要用6字節(jié)表示一個(gè)字符。
在UTF-8里,英文字符仍然跟ASCII編碼一樣,因此原先的函數(shù)庫(kù)可以繼續(xù)使用。而中文的編碼范圍是在0080-07FF之間,因此是2個(gè)字節(jié)表示(但這兩個(gè)字節(jié)和GB編碼的兩個(gè)字節(jié)是不同的),用專門的Unicode處理類可以對(duì)UTF編碼進(jìn)行處理。
下面說(shuō)說(shuō)中文的問題。
由于歷史的原因,在Unicode之前,一共存在過(guò)3套中文編碼標(biāo)準(zhǔn)。
GB2312-80,是中國(guó)大陸使用的國(guó)家標(biāo)準(zhǔn),其中一共編碼了6763個(gè)常用簡(jiǎn)體漢字。Big5,是臺(tái)灣使用的編碼標(biāo)準(zhǔn),編碼了臺(tái)灣使用的繁體漢字,大概有8千多個(gè)。HKSCS,是中國(guó)香港使用的編碼標(biāo)準(zhǔn),字體也是繁體,但跟Big5有所不同。
這3套編碼標(biāo)準(zhǔn)都采用了兩個(gè)擴(kuò)展ASCII的方法,因此,幾套編碼互不兼容,而且編碼區(qū)間也各有不同
因?yàn)槠洳患嫒菪裕谕粋€(gè)系統(tǒng)中同時(shí)顯示GB和Big5基本上是不可能的。當(dāng)時(shí)的南極星、RichWin等等軟件,在自動(dòng)識(shí)別中文編碼、自動(dòng)顯示正確編碼方面都做了很多努力
。
他們用了怎樣的技術(shù)我就不得而知了,我知道好像南極星曾經(jīng)以同屏顯示繁簡(jiǎn)中文為賣點(diǎn)。
后來(lái),由于各方面的原因,國(guó)際上又制定了針對(duì)中文的統(tǒng)一字符集GBK和GB18030,其中GBK已經(jīng)在Windows、Linux等多種操作系統(tǒng)中被實(shí)現(xiàn)。
GBK兼容GB2312,并增加了大量不常用漢字,還加入了幾乎所有的Big5中的繁體漢字。但是GBK中的繁體漢字和Big5中的幾乎不兼容。
GB18030相當(dāng)于是GBK的超集,比GBK包含的字符更多。據(jù)我所知目前還沒有操作系統(tǒng)直接支持GB18030。
談?wù)刄nicode編碼,簡(jiǎn)要解釋UCS、UTF、BMP、BOM等名詞
這是一篇程序員寫給程序員的趣味讀物。所謂趣味是指可以比較輕松地了解一些原來(lái)不清楚的概念,增進(jìn)知識(shí),類似于打RPG游戲的升級(jí)。整理這篇文章的動(dòng)機(jī)是兩個(gè)問題:
問題一:
使用Windows記事本的“另存為”,可以在GBK、Unicode、Unicode big
endian和UTF-8這幾種編碼方式間相互轉(zhuǎn)換。同樣是txt文件,Windows是怎樣識(shí)別編碼方式的呢?
我很早前就發(fā)現(xiàn)Unicode、Unicode big
endian和UTF-8編碼的txt文件的開頭會(huì)多出幾個(gè)字節(jié),分別是FF、FE(Unicode),FE、FF(Unicode big
endian),EF、BB、BF(UTF-8)。但這些標(biāo)記是基于什么標(biāo)準(zhǔn)呢?
問題二:
最 近在網(wǎng)上看到一個(gè)ConvertUTF.c,實(shí)現(xiàn)了UTF-32、UTF-16和UTF-8這三種編碼方式的相互轉(zhuǎn)換。對(duì)于Unicode(UCS2)、 GBK、UTF-8這些編碼方式,我原來(lái)就了解。但這個(gè)程序讓我有些糊涂,想不起來(lái)UTF-16和UCS2有什么關(guān)系。
查了查相關(guān)資料,總算將這些問題弄清楚了,順帶也了解了一些Unicode的細(xì)節(jié)。寫成一篇文章,送給有過(guò)類似疑問的朋友。本文在寫作時(shí)盡量做到通俗易懂,但要求讀者知道什么是字節(jié),什么是十六進(jìn)制。
0、big endian和little endian
big endian和little
endian是CPU處理多字節(jié)數(shù)的不同方式。例如“漢”字的Unicode編碼是6C49。那么寫到文件里時(shí),究竟是將6C寫在前面,還是將49寫在前面?如果將6C寫在前面,就是big
endian。還是將49寫在前面,就是little endian。
“endian”這個(gè)詞出自《格列佛游記》。小人國(guó)的內(nèi)戰(zhàn)就源于吃雞蛋時(shí)是究竟從大頭(Big-Endian)敲開還是從小頭(Little-Endian)敲開,由此曾發(fā)生過(guò)六次叛亂,其中一個(gè)皇帝送了命,另一個(gè)丟了王位。
我們一般將endian翻譯成“字節(jié)序”,將big endian和little
endian稱作“大尾”和“小尾”。
1、字符編碼、內(nèi)碼,順帶介紹漢字編碼
字符必須編碼后才能被計(jì)算機(jī)處理。計(jì)算機(jī)使用的缺省編碼方式就是計(jì)算機(jī)的內(nèi)碼。早期的計(jì)算機(jī)使用7位的ASCII編碼,為了處理漢字,程序員設(shè)計(jì)了用于簡(jiǎn)體中文的GB2312和用于繁體中文的big5。
GB2312(1980年)一共收錄了7445個(gè)字符,包括6763個(gè)漢字和682個(gè)其它符號(hào)。漢字區(qū)的內(nèi)碼范圍高字節(jié)從B0-F7,低字節(jié)從A1-FE,占用的碼位是72*94=6768。其中有5個(gè)空位是D7FA-D7FE。
GB2312 支持的漢字太少。1995年的漢字?jǐn)U展規(guī)范GBK1.0收錄了21886個(gè)符號(hào),它分為漢字區(qū)和圖形符號(hào)區(qū)。漢字區(qū)包括21003個(gè)字符。2000年的 GB18030是取代GBK1.0的正式國(guó)家標(biāo)準(zhǔn)。該標(biāo)準(zhǔn)收錄了27484個(gè)漢字,同時(shí)還收錄了藏文、蒙文、維吾爾文等主要的少數(shù)民族文字。現(xiàn)在的PC平 臺(tái)必須支持GB18030,對(duì)嵌入式產(chǎn)品暫不作要求。所以手機(jī)、MP3一般只支持GB2312。
從ASCII、GB2312、GBK到 GB18030,這些編碼方法是向下兼容的,即同一個(gè)字符在這些方案中總是有相同的編碼,后面的標(biāo)準(zhǔn)支持更多的字符。在這些編碼中,英文和中文可以統(tǒng)一地 處理。區(qū)分中文編碼的方法是高字節(jié)的最高位不為0。按照程序員的稱呼,GB2312、GBK到GB18030都屬于雙字節(jié)字符集
(DBCS)。
有的中文Windows的缺省內(nèi)碼還是GBK,可以通過(guò)GB18030升級(jí)包升級(jí)到GB18030。不過(guò)GB18030相對(duì)GBK增加的字符,普通人是很難用到的,通常我們還是用GBK指代中文Windows內(nèi)碼。
這里還有一些細(xì)節(jié):
GB2312的原文還是區(qū)位碼,從區(qū)位碼到內(nèi)碼,需要在高字節(jié)和低字節(jié)上分別加上A0。
在DBCS中,GB內(nèi)碼的存儲(chǔ)格式始終是big endian,即高位在前。
GB2312 的兩個(gè)字節(jié)的最高位都是1。但符合這個(gè)條件的碼位只有128*128=16384個(gè)。所以GBK和GB18030的低字節(jié)最高位都可能不是1。不過(guò)這不影 響DBCS字符流的解析:在讀取DBCS字符流時(shí),只要遇到高位為1的字節(jié),就可以將下兩個(gè)字節(jié)作為一個(gè)雙字節(jié)編碼,而不用管低字節(jié)的高位是什么。
2、Unicode、UCS和UTF
前面提到從ASCII、GB2312、GBK到GB18030的編碼方法是向下兼容的。而Unicode只與ASCII兼容(更準(zhǔn)確地說(shuō),是與ISO-8859-1兼容),與GB碼不兼容。例如“漢”字的Unicode編碼是6C49,而GB碼是BABA。
Unicode也是一種字符編碼方法,不過(guò)它是由國(guó)際組織設(shè)計(jì),可以容納全世界所有語(yǔ)言文字的編碼方案。Unicode的學(xué)名是”Universal
Multiple-Octet Coded Character Set”,簡(jiǎn)稱為UCS。UCS可以看作是”Unicode
Character Set”的縮寫。
根據(jù)維基百科全書(http://zh.wikipedia.org/wiki/)的記載:歷史上存在兩個(gè)試圖獨(dú)立設(shè)計(jì)Unicode的組織,即國(guó)際標(biāo)準(zhǔn)化組織(ISO)和一個(gè)軟件制造商的協(xié)會(huì)(unicode.org)。ISO開發(fā)了ISO
10646項(xiàng)目,Unicode協(xié)會(huì)開發(fā)了Unicode項(xiàng)目。
在1991年前后,雙方都認(rèn)識(shí)到世界不需要兩個(gè)不兼容的字符集。于是它們開始合并雙方的工作成果,并為創(chuàng)立一個(gè)單一編碼表而協(xié)同工作。從Unicode2.0開始,Unicode項(xiàng)目采用了與ISO
10646-1相同的字庫(kù)和字碼。
目前兩個(gè)項(xiàng)目仍都存在,并獨(dú)立地公布各自的標(biāo)準(zhǔn)。Unicode協(xié)會(huì)現(xiàn)在的最新版本是2005年的Unicode
4.1.0。ISO的最新標(biāo)準(zhǔn)是10646-3:2003。
UCS規(guī)定了怎么用多個(gè)字節(jié)表示各種文字。怎樣傳輸這些編碼,是由UTF(UCS
Transformation Format)規(guī)范規(guī)定的,常見的UTF規(guī)范包括UTF-8、UTF-7、UTF-16。
IETF的RFC2781和RFC3629以RFC的一貫風(fēng)格,清晰、明快又不失嚴(yán)謹(jǐn)?shù)孛枋隽薝TF-16和UTF-8的編碼方法。我總是記不得IETF是Internet
Engineering Task
Force的縮寫。但I(xiàn)ETF負(fù)責(zé)維護(hù)的RFC是Internet上一切規(guī)范的基礎(chǔ)。
3、UCS-2、UCS-4、BMP
UCS有兩種格式:UCS-2和UCS-4。顧名思義,UCS-2就是用兩個(gè)字節(jié)編碼,UCS-4就是用4個(gè)字節(jié)(實(shí)際上只用了31位,最高位必須為0)編碼。下面讓我們做一些簡(jiǎn)單的數(shù)學(xué)游戲:
UCS-2有2^16=65536個(gè)碼位,UCS-4有2^31=2147483648個(gè)碼位。
UCS-4根據(jù)最高位為0的最高字節(jié)分成2^7=128個(gè)group。每個(gè)group再根據(jù)次高字節(jié)分為256個(gè)plane。每個(gè)plane根據(jù)第3個(gè)字節(jié)分為256行
(rows),每行包含256個(gè)cells。當(dāng)然同一行的cells只是最后一個(gè)字節(jié)不同,其余都相同。
group 0的plane 0被稱作Basic Multilingual Plane,
即BMP。或者說(shuō)UCS-4中,高兩個(gè)字節(jié)為0的碼位被稱作BMP。
將UCS-4的BMP去掉前面的兩個(gè)零字節(jié)就得到了UCS-2。在UCS-2的兩個(gè)字節(jié)前加上兩個(gè)零字節(jié),就得到了UCS-4的BMP。而目前的UCS-4規(guī)范中還沒有任何字符被分配在BMP之外。
4、UTF編碼
UTF-8就是以8位為單元對(duì)UCS進(jìn)行編碼。從UCS-2到UTF-8的編碼方式如下:
UCS-2編碼(16進(jìn)制) UTF-8 字節(jié)流(二進(jìn)制)
0000 - 007F 0xxxxxxx
0080 - 07FF 110xxxxx 10xxxxxx
0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx
例如“漢”字的Unicode編碼是6C49。6C49在0800-FFFF之間,所以肯定要用3字節(jié)模板了:1110xxxx
10xxxxxx 10xxxxxx。將6C49寫成二進(jìn)制是:0110 110001 001001,
用這個(gè)比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。
讀者可以用記事本測(cè)試一下我們的編碼是否正確。
UTF -16以16位為單元對(duì)UCS進(jìn)行編碼。對(duì)于小于0×10000的UCS碼,UTF-16編碼就等于UCS碼對(duì)應(yīng)的16位無(wú)符號(hào)整數(shù)。對(duì)于不小于 0×10000的UCS碼,定義了一個(gè)算法。不過(guò)由于實(shí)際使用的UCS2,或者UCS4的BMP必然小于0×10000,所以就目前而言,可以認(rèn)為UTF -16和UCS-2基本相同。但UCS-2只是一個(gè)編碼方案,UTF-16卻要用于實(shí)際的傳輸,所以就不得不考慮字節(jié)序的問題。
5、UTF的字節(jié)序和BOM
UTF -8以字節(jié)為編碼單元,沒有字節(jié)序的問題。UTF-16以兩個(gè)字節(jié)為編碼單元,在解釋一個(gè)UTF-16文本前,首先要弄清楚每個(gè)編碼單元的字節(jié)序。例如收 到一個(gè)“奎”的Unicode編碼是594E,“乙”的Unicode編碼是4E59。如果我們收到UTF-16字節(jié)流“594E”,那么這是“奎”還是 “乙”?
Unicode規(guī)范中推薦的標(biāo)記字節(jié)順序的方法是BOM。BOM不是“Bill Of
Material”的BOM表,而是Byte Order Mark。BOM是一個(gè)有點(diǎn)小聰明的想法:
在UCS編碼中有一個(gè)叫做”ZERO WIDTH NO-BREAK
SPACE”的字符,它的編碼是FEFF。而FFFE在UCS中是不存在的字符,所以不應(yīng)該出現(xiàn)在實(shí)際傳輸中。UCS規(guī)范建議我們?cè)趥鬏斪止?jié)流前,先傳輸字符”ZERO
WIDTH NO-BREAK SPACE”。
這樣如果接收者收到FEFF,就表明這個(gè)字節(jié)流是Big-Endian的;如果收到FFFE,就表明這個(gè)字節(jié)流是Little-Endian的。因此字符”ZERO
WIDTH NO-BREAK SPACE”又被稱作BOM。
UTF-8不需要BOM來(lái)表明字節(jié)順序,但可以用BOM來(lái)表明編碼方式。字符”ZERO
WIDTH NO-BREAK SPACE”的UTF-8編碼是EF BB
BF(讀者可以用我們前面介紹的編碼方法驗(yàn)證一下)。所以如果接收者收到以EF BB
BF開頭的字節(jié)流,就知道這是UTF-8編碼了。
Windows就是使用BOM來(lái)標(biāo)記文本文件的編碼方式的。
6、進(jìn)一步的參考資料
本文主要參考的資料是 “Short overview of ISO-IEC 10646 and Unicode”
(http://www.nada.kth.se/i18n/ucs/unicode-iso10646-oview.html)。
我還找了兩篇看上去不錯(cuò)的資料,不過(guò)因?yàn)槲议_始的疑問都找到了答案,所以就沒有看:
“Understanding Unicode A general introduction to the Unicode Standard”
(http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&item_id=IWS-Chapter04a)
“Character set encoding basics Understanding character set encodings
and legacy encodings”
(http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&item_id=IWS-Chapter03)
附錄1 再說(shuō)說(shuō)區(qū)位碼、GB2312、內(nèi)碼和代碼頁(yè)
有的朋友對(duì)文章中這句話還有疑問: “GB2312的原文還是區(qū)位碼,從區(qū)位碼到內(nèi)碼,需要在高字節(jié)和低字節(jié)上分別加上A0。”
我再詳細(xì)解釋一下:
“GB2312 的原文”是指國(guó)家1980年的一個(gè)標(biāo)準(zhǔn)《中華人民共和國(guó)國(guó)家標(biāo)準(zhǔn) 信息交換用漢字編碼字符集 基本集 GB 2312-80》。這個(gè)標(biāo)準(zhǔn)用兩個(gè)數(shù)來(lái)編碼漢字和中文符號(hào)。第一個(gè)數(shù)稱為“區(qū)”,第二個(gè)數(shù)稱為“位”。所以也稱為區(qū)位碼。1-9區(qū)是中文符號(hào),16-55 區(qū)是一級(jí)漢字,56-87區(qū)是二級(jí)漢字。現(xiàn)在Windows也還有區(qū)位輸入法,例如輸入1601得到“啊”。
內(nèi)碼是指操作系統(tǒng)內(nèi)部的字符 編碼。早期操作系統(tǒng)的內(nèi)碼是與語(yǔ)言相關(guān)的.現(xiàn)在的Windows在內(nèi)部統(tǒng)一使用Unicode,然后用代碼頁(yè)適應(yīng)各種語(yǔ)言,“內(nèi)碼”的概念就比較模糊了。 微軟一般將缺省代碼頁(yè)指定的編碼說(shuō)成是內(nèi)碼,在特殊的場(chǎng)合也會(huì)說(shuō)自己的內(nèi)碼是Unicode,例如在 GB18030問題的處理上。
所謂代碼頁(yè)(code page)就是針對(duì)一種語(yǔ)言文字的字符編碼。例如GBK的code page是CP936,BIG5的code page是CP950,GB2312的code page是CP20936。
Windows中有缺省代碼頁(yè)的概念,即缺省用什么編碼來(lái)解釋字符。例如Windows的記事本打開了一個(gè)文本文件,里面的內(nèi)容是字節(jié)流:BA、BA、D7、D6。Windows應(yīng)該去怎么解釋它呢?
是 按照Unicode編碼解釋、還是按照GBK解釋、還是按照BIG5解釋,還是按照ISO8859-1去解釋?如果按GBK去解釋,就會(huì)得到“漢字”兩個(gè) 字。按照其它編碼解釋,可能找不到對(duì)應(yīng)的字符,也可能找到錯(cuò)誤的字符。所謂“錯(cuò)誤”是指與文本作者的本意不符,這時(shí)就產(chǎn)生了亂碼。
答案是Windows按照當(dāng)前的缺省代碼頁(yè)去解釋文本文件里的字節(jié)流。缺省代碼頁(yè)可以通過(guò)控制面板的區(qū)域選項(xiàng)設(shè)置。記事本的另存為中有一項(xiàng)ANSI,其實(shí)就是按照缺省代碼頁(yè)的編碼方法保存。
Windows的內(nèi)碼是Unicode,它在技術(shù)上可以同時(shí)支持多個(gè)代碼頁(yè)。只要文件能說(shuō)明自己使用什么編碼,用戶又安裝了對(duì)應(yīng)的代碼頁(yè),Windows就能正確顯示,例如在HTML文件中就可以指定charset。
有 的HTML文件作者,特別是英文作者,認(rèn)為世界上所有人都使用英文,在文件中不指定charset。如果他使用了0×80-0xff之間的字符,中文 Windows又按照缺省的GBK去解釋,就會(huì)出現(xiàn)亂碼。這時(shí)只要在這個(gè)html文件中加上指定charset的語(yǔ)句,例如:如果原作者使用的代碼頁(yè)和 ISO8859-1兼容,就不會(huì)出現(xiàn)亂碼了。
再說(shuō)區(qū)位碼,啊的區(qū)位碼是1601,寫成16進(jìn)制是0×10,0×01。這和計(jì)算機(jī)廣泛使用 的ASCII編碼沖突。為了兼容00-7f的 ASCII編碼,我們?cè)趨^(qū)位碼的高、低字節(jié)上分別加上A0。這樣“啊”的編碼就成為B0A1。我們將加過(guò)兩個(gè)A0的編碼也稱為GB2312編碼,雖然 GB2312的原文根本沒提到這一點(diǎn)。
本文來(lái)源于 冰山上的播客 http://xinsync.xju.edu.cn , 原文地址:http://xinsync.xju.edu.cn/index.php/archives/483
posted @
2008-10-16 09:50 華夢(mèng)行 閱讀(2329) |
評(píng)論 (0) |
編輯 收藏
$curl = curl_init();?
curl_setopt(
$curl, CURLOPT_URL, 'http://????????'); ?
curl_setopt(
$curl, CURLOPT_RETURNTRANSFER, 1); ?
curl_setopt(
$curl, CURLOPT_CONNECTTIMEOUT, 10); ?
$str = curl_exec(
$curl); ?
curl_close($curl); ?
?
$html=
str_get_html($str);?
posted @
2008-10-15 14:29 華夢(mèng)行 閱讀(366) |
評(píng)論 (0) |
編輯 收藏
trace(("中國(guó)").charCodeAt(0));? 21106 他們返回的值相同
System.out.println("中國(guó)".codePointAt(0));? 如果再求余的話,就可以產(chǎn)生隨機(jī)數(shù)
posted @
2008-10-15 11:19 華夢(mèng)行 閱讀(209) |
評(píng)論 (0) |
編輯 收藏
String keywords=new String(request.getParameter("mname").getBytes("ISO-8859-1"), "gbk");
posted @
2008-10-14 15:54 華夢(mèng)行 閱讀(139) |
評(píng)論 (0) |
編輯 收藏
mysql 創(chuàng)建 數(shù)據(jù)庫(kù)時(shí)指定編碼很重要,很多開發(fā)者都使用了默認(rèn)編碼,但是我使用的經(jīng)驗(yàn)來(lái)看,制定數(shù)據(jù)庫(kù)的編碼可以很大程度上避免倒入導(dǎo)出帶來(lái)的亂碼問題。
我們遵循的標(biāo)準(zhǔn)是,數(shù)據(jù)庫(kù),表,字段和頁(yè)面或文本的編碼要統(tǒng)一起來(lái)
很多mysql數(shù)據(jù)庫(kù)工具(除了phpmyadmin,我偶爾用,功能強(qiáng)速度慢)都不支持創(chuàng)建時(shí)指定數(shù)據(jù)庫(kù)編碼,當(dāng)然可以改my.ini來(lái)解決這個(gè)問題,但是需要重新啟動(dòng)mysql,
不過(guò)用下面的語(yǔ)句會(huì)更有效
GBK: create database test2 DEFAULT CHARACTER SET gbk COLLATE gbk_chinese_ci;
UTF8: CREATE DATABASE `test2` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci
posted @
2008-10-13 10:00 華夢(mèng)行 閱讀(281) |
評(píng)論 (0) |
編輯 收藏
6.5.4 ? ALTER ? TABLE ? 句法???
添加唯一
ALTER? table justmusic add unique? (musicsource)
????
????
? ALTER ? TABLE ? 允許你改變一個(gè)現(xiàn)有表的結(jié)構(gòu)。例如,你可以添加或刪除列,創(chuàng)建或撤銷索引,更改現(xiàn)有列的類型或?qū)⒘谢虮碜陨砀D阋部梢愿淖儽淼淖⑨尯捅淼念愋汀2榭凑鹿?jié) ? 6.5.3 ? CREATE ? TABLE ? 句法。 ? ?
? ?
? 如果你使用 ? ALTER ? TABLE ? 來(lái)改變一個(gè)列規(guī)約,但是 ? DESCRIBE ? tbl_name ? 顯示你的列并沒有被修改,這有可能是因?yàn)檎鹿?jié) ? 6.5.3.1 ? 隱式的列定義變化 ? 描述的一個(gè)原因,使 ? MySQL ? 忽略了你的修改。例如,如果你嘗試將一個(gè) ? VARCHAR ? 列更改為 ? CHAR,而如果在這個(gè)表中包含其它的變長(zhǎng)列,MySQL ? 將仍然使用 ? VARCHAR。 ? ?
? ?
? ALTER ? TABLE ? 通過(guò)建立原初表的一個(gè)臨時(shí)副本來(lái)工作。更改在副本上執(zhí)行,然后原初表將被刪除,臨時(shí)表被換名。這樣做使所有的修改自動(dòng)地轉(zhuǎn)向到?jīng)]有任何更新失敗的新表。當(dāng) ? ALTER ? TABLE ? 執(zhí)行時(shí),原初表可被其它客戶端讀取。更新與寫入被延遲到新的表準(zhǔn)備好。 ? ?
? ?
? 注意,如果你以除 ? RENAME ? 之外的其它選項(xiàng)使用 ? ALTER ? TABLE ? ,MySQL ? 將總是創(chuàng)建一個(gè)臨時(shí)表,即使數(shù)據(jù)并不確實(shí)需要被復(fù)制(就像當(dāng)你改變一個(gè)列名時(shí))。我們計(jì)劃不久來(lái)修正它,但是通常人們是不經(jīng)常執(zhí)行 ? ALTER ? TABLE的,所以在我們的 ? TODO ? 上,這個(gè)修正并不是急于處理的。對(duì)于 ? MyISAM ? 表,你可以將變量 ? myisam_sort_buffer_size ? 設(shè)置和高一點(diǎn),以加速索引的重建部分(這是重建進(jìn)程中最慢的部分)。 ? ?
? ?
? 為了使用 ? ALTER ? TABLE,你需要在這個(gè)表上有 ? ALTER、INSERT ? 和 ? CREATE ? 權(quán)限。 ? ?
? ?
? IGNORE ? 是 ? MySQL ? 對(duì) ? ANSI ? SQL92 ? 的擴(kuò)展。它用于控制當(dāng)在新表中的唯一鍵上出現(xiàn)重復(fù)值時(shí),ALTER ? TABLE ? 如何工作。如果 ? IGNORE ? 沒有被指定,副本將被放棄并回退。如果 ? IGNORE ? 被指定,那么在唯一鍵上重復(fù)的記錄行只有第一個(gè)記錄行被使用;其它的均被刪除。 ? ?
? ?
? 你可以在單個(gè)的 ? ALTER ? TABLE ? 語(yǔ)句中發(fā)出多個(gè) ? ADD、ALTER、DROP ? 和 ? CHANGE ? 子句。這是 ? MySQL ? 對(duì) ? ANSI ? SQL92 ? 的擴(kuò)展,ANSI ? SQL92 ? 只允許在每個(gè) ? ALTER ? TABLE ? 語(yǔ)句中一個(gè)子句。 ? ?
? ?
? CHANGE ? col_name、DROP ? col_name ? 和 ? DROP ? INDEX ? 是 ? MySQL ? 對(duì) ? ANSI ? SQL92 ? 的擴(kuò)展。 ? ?
? ?
? MODIFY ? is ? an ? Oracle ? extension ? to ? ALTER ? TABLE. ? ?
? 可選詞 ? COLUMN ? 只是一個(gè)無(wú)用詞組,可被忽略。 ? ?
? ?
? 如果你使用 ? ALTER ? TABLE ? tbl_name ? RENAME ? TO ? new_name,并沒有任何其它的選項(xiàng),MySQL ? 將簡(jiǎn)單地重命名與表 ? tbl_name ? 的文件。這不需要?jiǎng)?chuàng)建臨時(shí)表。查看章節(jié) ? 6.5.5 ? RENAME ? TABLE ? 句法。 ? ?
? ?
? create_definition ? 子句使用與 ? CREATE ? TABLE ? 相同的 ? ADD ? 和 ? CHANGE ? 句法。注意,這些句法不僅包含列類型,還要包含列名。查看章節(jié) ? 6.5.3 ? CREATE ? TABLE ? 句法。 ? ?
? ?
? 你可以使用一個(gè) ? CHANGE ? old_col_name ? create_definition ? 子句來(lái)重命名一個(gè)列。為了這樣做,你必須指定舊的和新的列名,以及列當(dāng)前的類型。例如,為了將一個(gè) ? INTEGER ? 列 ? a ? 重命名為 ? b,你必須這樣做: ? ?
? mysql> ? ALTER ? TABLE ? t1 ? CHANGE ? a ? b ? INTEGER; ?
? ?
? 如果你希望改變一個(gè)列的類型而不是列名,CHANGE ? 句法仍然需要有兩個(gè)列名,即使它們是一樣的。例如: ? ?
? mysql> ? ALTER ? TABLE ? t1 ? CHANGE ? b ? b ? BIGINT ? NOT ? NULL; ?
? ?
? 然后,到 ? MySQL ? 3.22.16a ? 時(shí),你也可以使用 ? MODIFY ? 來(lái)改變一個(gè)列的類型而不需要重命名它: ? ?
? mysql> ? ALTER ? TABLE ? t1 ? MODIFY ? b ? BIGINT ? NOT ? NULL; ?
? ?
? 如果你使用 ? CHANGE ? 或 ? MODIFY ? 縮短一個(gè)列,而該列上存在一個(gè)取列部分值的索引(舉例來(lái)說(shuō),如果你有一個(gè)索引在一個(gè) ? VARCHAR ? 列的前 ? 10 ? 個(gè)字符上),那么,你將不能使列短于索引的字符數(shù)目。 ? ?
? ?
? 當(dāng)你使用 ? CHANGE ? 或 ? MODIFY ? 改變一個(gè)列類型時(shí),MySQL ? 將嘗試盡可能地將數(shù)據(jù)轉(zhuǎn)換到新的類型。 ? ?
? ?
? 在 ? MySQL ? 3.22 ? 或更新的版本中,你可以使用 ? FIRST ? 或 ? ADD ? ... ? AFTER ? col_name ? 在一個(gè)表中的某個(gè)特定位置添加一列。缺省是增加到最后一列。從 ? MySQL ? 4.0.1 ? 開始,你也可以在 ? CHANGE ? 或 ? MODIFY ? 中使用關(guān)鍵詞 ? FIRST ? 和 ? AFTER ? 。 ? ?
? ?
? ALTER ? COLUMN ? 可以為一列指定一個(gè)新的缺省值或刪除老的缺省值。如果老的缺省值被移除且列可以被設(shè)為 ? NULL,新的缺省值將是 ? NULL。如果該列不允許有 ? NULL值,MySQL ? 以章節(jié) ? 6.5.3 ? CREATE ? TABLE ? 句法 ? 中的描述方式為該列賦于一個(gè)缺省值。 ? ?
? ?
? DROP ? INDEX ? 移除一個(gè)索引。這是 ? MySQL ? 對(duì) ? ANSI ? SQL92 ? 的一個(gè)擴(kuò)展。查看章節(jié) ? 6.5.8 ? DROP ? INDEX ? 句法。 ? ?
? ?
? 如果列被從一個(gè)表中移除,列也將從任何有它為組成部分的索引中被移除。如果組成一個(gè)索引的所有列均被移除了,那么,該索引也將被移除。 ? ?
? ?
? 如果一個(gè)表只包含一個(gè)列,那么該列不能被移除。如果你本就打算移除該表,請(qǐng)使用 ? DROP ? TABLE ? 代替。 ? ?
? ?
? DROP ? PRIMARY ? KEY ? 移除主索引。如果這樣的索引不存在,它將移除表中的第一個(gè) ? UNIQUE ? 索引。(如果沒有 ? PRIMARY ? KEY ? 被明確指定,MySQL ? 將第一個(gè) ? UNIQUE ? 鍵標(biāo)記為 ? PRIMARY ? KEY ? ) ? 如果你添加一個(gè) ? UNIQUE ? INDEX ? 或 ? PRIMARY ? KEY ? 到一個(gè)表中,它將被存儲(chǔ)在任何非 ? UNIQUE ? 索引之前,因而,MySQL ? 可以盡可能地檢測(cè)出重復(fù)鍵。 ? ?
? ?
? ORDER ? BY ? 允許你以指定的記錄行順序創(chuàng)建一個(gè)新表。注意,在插入與刪除后,該表將不會(huì)保留這個(gè)順序。在某些情況下,如果表在你以后希望排序的列上是有序的,這將使得 ? MySQL ? 排序時(shí)更加得容易。當(dāng)你知道你主要查詢的行以一個(gè)確定的次序時(shí),這將是很有用的。在對(duì)表進(jìn)行過(guò)大的改變后,通過(guò)使用這個(gè)選項(xiàng),你可能會(huì)得到更高的性能。 ? ?
? ?
? 如果你在一個(gè) ? MyISAM ? 表上使用 ? ALTER ? TABLE ? ,所有非唯一的索引將以一個(gè)分批方式創(chuàng)建(就像 ? REPAIR ? 一樣)。當(dāng)你有很多索引時(shí),這可能使 ? ALTER ? TABLE ? 更快一點(diǎn)。 ? ?
? ?
? 從 ? MySQL ? 4.0 ? 開始,上面的特性可明確地激活。ALTER ? TABLE ? ... ? DISABLE ? KEYS ? 使 ? MySQL ? 停止更新 ? MyISAM ? 表的非唯一索引。然后 ? ALTER ? TABLE ? ... ? ENABLE ? KEYS ? 可以被用來(lái)重建丟失的索引。因?yàn)?? MySQL ? 以特殊的算法執(zhí)行它,這將比一個(gè)接一個(gè)地插入索引要快得多,禁用鍵可以很大程序上的加速一個(gè)大批量的插入。 ? ?
? ?
? 使用 ? C ? API ? 函數(shù) ? mysql_info(),你可以找出有多少記錄被拷貝,以及(當(dāng) ? IGNORE ? 被使用時(shí))有多少記錄因唯一鍵值重復(fù)而被刪除。 ? ?
? ?
? FOREIGN ? KEY、CHECK ? 和 ? REFERENCES ? 子句實(shí)際上不做任何事情,除了對(duì)于 ? InnoDB ? 類型的表,它支持 ? ADD ? CONSTRAINT ? FOREIGN ? KEY ? (...) ? REFERENCES ? ... ? (...)。注意,InnoDB ? 不允許一個(gè) ? index_name ? 被指定。查看章節(jié) ? 7.5 ? InnoDB ? 表。對(duì)于其它類型的表,這個(gè)句法僅僅為了兼容而提供,以更容易地從其它 ? SQL ? 服務(wù)器移植代碼和更容易地運(yùn)行以引用創(chuàng)建表的應(yīng)用程序。查看章節(jié) ? 1.8.4 ? MySQL ? 與 ? ANSI ? SQL92 ? 相比不同的差別。 ? ?
? 這里是一個(gè)例子,顯示了 ? ALTER ? TABLE ? 的一些用法。我們以一個(gè)按如下方式創(chuàng)建一個(gè)表 ? t1 ? 開始: ? ?
? ?
? mysql> ? CREATE ? TABLE ? t1 ? (a ? INTEGER,b ? CHAR(10)); ?
? ?
? 為了將表 ? t1 ? 重命名為 ? t2: ? ?
? ?
? mysql> ? ALTER ? TABLE ? t1 ? RENAME ? t2; ?
? ?
? 為了將列 ? a ? 從 ? INTEGER ? 改變?yōu)?? TINYINT ? NOT ? NULL(列名不變),并將列 ? b ? 從 ? CHAR(10) ? 改變?yōu)?? CHAR(20) ? ,同時(shí)也將 ? b ? 重命名為 ? c: ? ?
? ?
? mysql> ? ALTER ? TABLE ? t2 ? MODIFY ? a ? TINYINT ? NOT ? NULL, ? CHANGE ? b ? c ? CHAR(20); ?
? ?
? 添加一個(gè)名為 ? d ? 的 ? TIMESTAMP ? c列: ? ?
? ?
? mysql> ? ALTER ? TABLE ? t2 ? ADD ? d ? TIMESTAMP; ?
? ?
? 在列 ? d ? 上增加一個(gè)索引,將列 ? a ? 設(shè)為主鍵: ? ?
? ?
? mysql> ? ALTER ? TABLE ? t2 ? ADD ? INDEX ? (d), ? ADD ? PRIMARY ? KEY ? (a); ?
? ?
? 移除列 ? c: ? ?
? ?
? mysql> ? ALTER ? TABLE ? t2 ? DROP ? COLUMN ? c; ?
? ?
? 添加一個(gè)名為 ? c ? 的 ? AUTO_INCREMENT ? 整型列: ? ?
? ?
? mysql> ? ALTER ? TABLE ? t2 ? ADD ? c ? INT ? UNSIGNED ? NOT ? NULL ? AUTO_INCREMENT, ?
? ? ? ? ? ? ? ? ? ? ? ? ADD ? INDEX ? (c); ?
? ?
? 注意,我們索引了 ? c,因?yàn)?? AUTO_INCREMENT ? 列必須被索引,同樣我們聲明列 ? c ? 為 ? NOT ? NULL,因?yàn)楸凰饕牧胁荒苡?? NULL。 ? ?
? ?
? 當(dāng)你添加一個(gè) ? AUTO_INCREMENT ? 列時(shí),列值會(huì)自動(dòng)地以序列值填充。通過(guò)在 ? ALTER ? TABLE ? 或使用 ? AUTO_INCREMENT ? = ? # ? 表選項(xiàng)之前執(zhí)行 ? SET ? INSERT_ID=# ? ,你可以設(shè)置第一個(gè)序列數(shù)字。查看章節(jié) ? 5.5.6 ? SET ? 句法。 ? ?
? ?
? 對(duì)于 ? MyISAM ? 表,如果你不改變 ? AUTO_INCREMENT ? 列,序列值將不會(huì)被影響。如果你移除一個(gè)AUTO_INCREMENT ? 列,并添加另一個(gè) ? AUTO_INCREMENT ? 列,值將再次從 ? 1 ? 開始。?????
??
???
posted @
2008-10-10 18:00 華夢(mèng)行 閱讀(4849) |
評(píng)論 (0) |
編輯 收藏
最近發(fā)現(xiàn)用htmlparser解析一些網(wǎng)頁(yè)時(shí),繁體中文會(huì)變成亂碼.分析了下原因,發(fā)現(xiàn)在用stringbean的時(shí)候htmlparser會(huì)自己根據(jù)meta來(lái)決定用哪種內(nèi)碼來(lái)解碼,而有的網(wǎng)站在meta中是用gb2312來(lái)做charset,實(shí)際應(yīng)用的時(shí)候又用到了gbk.gb2312是不能表示繁體的,所以就出現(xiàn)了亂碼.解決的辦法很簡(jiǎn)單,gbk是兼容gb2312的,所以在htmlparser的page.java的getcharser()那里加一句判斷,如果ret是gb2312就設(shè)置為gbk,這樣問題就解決了.?
修改的page.java的代碼如下(/lexer/page.java)
??? public String getCharset (String content)
??? {
??????? final String CHARSET_STRING = "charset";
??????? int index;
??????? String ret;
??????? if (null == mSource)
??????????? ret = DEFAULT_CHARSET;
??????? else
??????????? // use existing (possibly supplied) character set:
??????????? // bug #1322686 when illegal charset specified
??????????? ret = mSource.getEncoding ();
??????? if (null != content)
??????? {
??????????? index = content.indexOf (CHARSET_STRING);
??????????? if (index != -1)
??????????? {
??????????????? content = content.substring (index +
??????????????????? CHARSET_STRING.length ()).trim ();
??????????????? if (content.startsWith ("="))
??????????????? {
??????????????????? content = content.substring (1).trim ();
??????????????????? index = content.indexOf (";");
??????????????????? if (index != -1)
??????????????????????? content = content.substring (0, index);
??????????????????? //remove any double quotes from around charset string
??????????????????? if (content.startsWith ("\"") && content.endsWith ("\"")
??????????????????????? && (1 < content.length ()))
??????????????????????? content = content.substring (1, content.length () - 1);
??????????????????? //remove any single quote from around charset string
??????????????????? if (content.startsWith ("'") && content.endsWith ("'")
??????????????????????? && (1 < content.length ()))
??????????????????????? content = content.substring (1, content.length () - 1);
??????????????????? ret = findCharset (content, ret);
??????????????????? // Charset names are not case-sensitive;
??????????????????? // that is, case is always ignored when comparing
??????????????????? // charset names.
//??????????????????? if (!ret.equalsIgnoreCase (content))
//??????????????????? {
//??????????????????????? System.out.println (
//??????????????????????????? "detected charset \""
//??????????????????????????? + content
//??????????????????????????? + "\", using \""
//??????????????????????????? + ret
//??????????????????????????? + "\"");
//??????????????????? }
??????????????? }
??????????? }
??????? }
??????? if(ret.equalsIgnoreCase("gb2312"))ret="GBK"; //to avoid decode problem
??????????????????????????????????????????????????????????????????????????????????????? ? ?//edited by linyunfan
??????? return (ret);
??? }
?
在最后加入了這句
??????? if(ret.equalsIgnoreCase("gb2312"))ret="GBK";
posted @
2008-10-09 13:33 華夢(mèng)行 閱讀(1772) |
評(píng)論 (3) |
編輯 收藏
發(fā)現(xiàn)了一個(gè)很不錯(cuò)的電影網(wǎng)站,
http://www.mdianying.com?收藏一下
posted @
2008-09-26 14:36 華夢(mèng)行 閱讀(541) |
評(píng)論 (2) |
編輯 收藏
.TEXTAREA{
73
border: #999999 1px solid; font-size:14px; color:#333; font-family:Georgia, "Times New Roman", Times, serif; margin-bottom:2px; width:100%; height:115px; background:url(../images/inLogin.jpg) no-repeat 50% 50%;
74
scrollbar-arrow-color:#999; /*上下按鈕上三角箭頭的顏色*/
75
scrollbar-base-color:#999;/*滾動(dòng)條的基本顏色*/
76
scrollbar-dark-shadow-color:#99CCFF;/*立體滾動(dòng)條強(qiáng)陰影的顏色*/
77
scrollbar-face-color:#999;/*立體滾動(dòng)條凸出部分的顏色*/
78
scrollbar-highlight-color:#fff;/*滾動(dòng)條空白部分的顏色*/
79
scrollbar-shadow-color:#fff;/*立體滾動(dòng)條陰影的顏色*/
80
}
posted @
2008-09-24 10:44 華夢(mèng)行 閱讀(183) |
評(píng)論 (0) |
編輯 收藏
package org.igniterealtime.xiff.util
{
?//import mx.formatters.DateFormatter;
?public class Util
?{
??public function Util()
??{
??}
??????? public static function getNowDateFormat():String{??????? ?
??????? ? return (new Date().toTimeString().substr(0,8));
??? }??
??public static function getGenerate():String{
????? ?var i:int=Math.random()*99;
????? ?return i.toString();
????? }
??? public static function trim(str:String):String
????? {
?????????? var myPattern:RegExp = /</g;
??? str=str.replace(myPattern, "");? ???
??? if (str == null) return '';
????????? var startIndex:int = 0;
????????? while (isWhitespace(str.charAt(startIndex)))
????????????? ++startIndex;
??
????????? var endIndex:int = str.length - 1;
????????? while (isWhitespace(str.charAt(endIndex)))
????????????? --endIndex;
??
????????? if (endIndex >= startIndex)
????????????? return str.slice(startIndex, endIndex + 1);
????????? else
????????????? return "";
????? }
?public static function isWhitespace(character:String):Boolean
????? {
????????? switch (character)
????????? {
????????????? case " ":
????????????? case "\t":
????????????? case "\r":
????????????? case "\n":
????????????? case "\f":
????????????????? return true;
??
????????????? default:
????????????????? return false;
????????? }
????? }
???
??? }
?
}
posted @
2008-09-24 09:42 華夢(mèng)行 閱讀(268) |
評(píng)論 (0) |
編輯 收藏
public class Escape {
??????? private final static String[] hex = { "00", "01", "02", "03", "04", "05",
??????? "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F", "10",
??????? "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B",
??????? "1C", "1D", "1E", "1F", "20", "21", "22", "23", "24", "25", "26",
??????? "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", "30", "31",
??????? "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C",
??????? "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47",
??????? "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52",
??????? "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D",
??????? "5E", "5F", "60", "61", "62", "63", "64", "65", "66", "67", "68",
??????? "69", "6A", "6B", "6C", "6D", "6E", "6F", "70", "71", "72", "73",
??????? "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E",
??????? "7F", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
??????? "8A", "8B", "8C", "8D", "8E", "8F", "90", "91", "92", "93", "94",
??????? "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
??????? "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA",
??????? "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3", "B4", "B5",
??????? "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF", "C0",
??????? "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB",
??????? "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6",
??????? "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1",
??????? "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC",
??????? "ED", "EE", "EF", "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7",
??????? "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF" };
??????? private final static byte[] val = { 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
??????? 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
??????? 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
??????? 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
??????? 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x00, 0x01,
??????? 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x3F, 0x3F, 0x3F,
??????? 0x3F, 0x3F, 0x3F, 0x3F, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x3F,
??????? 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
??????? 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
??????? 0x3F, 0x3F, 0x3F, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x3F, 0x3F,
??????? 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
??????? 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
??????? 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
??????? 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
??????? 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
??????? 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
??????? 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
??????? 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
??????? 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
??????? 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
??????? 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
??????? 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
??????? 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
??????? 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F };
??????? /**
??????? * 編碼
??????? *
??????? * @param s
??????? * @return
??????? */
??????? public static String escape(String s) {
??????? StringBuffer sbuf = new StringBuffer();
??????? int len = s.length();
??????? for (int i = 0; i < len; i++) {
??????? int ch = s.charAt(i);
??????? if ('A' <= ch && ch <= 'Z') { // 'A'..'Z' : as it was
??????? sbuf.append((char) ch);
??????? } else if ('a' <= ch && ch <= 'z') { // 'a'..'z' : as it was
??????? sbuf.append((char) ch);
??????? } else if ('0' <= ch && ch <= '9') { // '0'..'9' : as it was
??????? sbuf.append((char) ch);
??????? } else if (ch == '-' || ch == '_' // unreserved : as it was
??????? || ch == '.' || ch == '!' || ch == '~' || ch == '*'
??????? || ch == '\'' || ch == '(' || ch == ')') {
??????? sbuf.append((char) ch);
??????? } else if (ch <= 0x007F) { // other ASCII : map to %XX
??????? sbuf.append('%');
??????? sbuf.append(hex[ch]);
??????? } else { // unicode : map to %uXXXX
??????? sbuf.append('%');
??????? sbuf.append('u');
??????? sbuf.append(hex[(ch >>> 8)]);
??????? sbuf.append(hex[(0x00FF & ch)]);
??????? }
??????? }
??????? return sbuf.toString();
??????? }
??????? /**
??????? * 解碼 說(shuō)明:本方法保證 不論參數(shù)s是否經(jīng)過(guò)escape()編碼,均能得到正確的“解碼”結(jié)果
??????? *
??????? * @param s
??????? * @return
??????? */
??????? public static String unescape(String s) {
??????? StringBuffer sbuf = new StringBuffer();
??????? int i = 0;
??????? int len = s.length();
??????? while (i < len) {
??????? int ch = s.charAt(i);
??????? if ('A' <= ch && ch <= 'Z') { // 'A'..'Z' : as it was
??????? sbuf.append((char) ch);
??????? } else if ('a' <= ch && ch <= 'z') { // 'a'..'z' : as it was
??????? sbuf.append((char) ch);
??????? } else if ('0' <= ch && ch <= '9') { // '0'..'9' : as it was
??????? sbuf.append((char) ch);
??????? } else if (ch == '-' || ch == '_' // unreserved : as it was
??????? || ch == '.' || ch == '!' || ch == '~' || ch == '*'
??????? || ch == '\'' || ch == '(' || ch == ')') {
??????? sbuf.append((char) ch);
??????? } else if (ch == '%') {
??????? int cint = 0;
??????? if ('u' != s.charAt(i + 1)) { // %XX : map to ascii(XX)
??????? cint = (cint << 4) | val[s.charAt(i + 1)];
??????? cint = (cint << 4) | val[s.charAt(i + 2)];
??????? i += 2;
??????? } else { // %uXXXX : map to unicode(XXXX)
??????? cint = (cint << 4) | val[s.charAt(i + 2)];
??????? cint = (cint << 4) | val[s.charAt(i + 3)];
??????? cint = (cint << 4) | val[s.charAt(i + 4)];
??????? cint = (cint << 4) | val[s.charAt(i + 5)];
??????? i += 5;
??????? }
??????? sbuf.append((char) cint);
??????? } else { // 對(duì)應(yīng)的字符未經(jīng)過(guò)編碼
??????? sbuf.append((char) ch);
??????? }
??????? i++;
??????? }
??????? return sbuf.toString();
??????? }
??????? public static void main(String[] args) {
??????? String stest = "中文1234 abcd[]()<+>,.~\\";
??????? System.out.println(stest);
??????? System.out.println(escape(stest));
??????? System.out.println(unescape(escape(stest)));
??????? }
??????? }
?
posted @
2008-09-24 09:00 華夢(mèng)行 閱讀(208) |
評(píng)論 (0) |
編輯 收藏