<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-295  評(píng)論-26  文章-1  trackbacks-0
     

    創(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ò)目錄

    1. 本文目標(biāo)
    2. 如何使用本教程
    3. 正則表達(dá)式到底是什么東西?
    4. 入門
    5. 測(cè)試正則表達(dá)式
    6. 元字符
    7. 字符轉(zhuǎn)義
    8. 重復(fù)
    9. 字符類
    10. 分枝條件
    11. 反義
    12. 分組
    13. 后向引用
    14. 零寬斷言
    15. 負(fù)向零寬斷言
    16. 注釋
    17. 貪婪與懶惰
    18. 處理選項(xiàng)
    19. 平衡組/遞歸匹配
    20. 還有些什么東西沒提到
    21. 聯(lián)系作者
    22. 最后,來(lái)點(diǎn)廣告...
    23. 網(wǎng)上的資源及本文參考文獻(xiàn)
    24. 更新說(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-123456780376-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á)式

    其它可用的測(cè)試工具:

    如果你不覺得正則表達(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í)的截圖:

    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.comC:\\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ì)匹配singdanc

    (?<=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)編輯 收藏

    JDK1.6官方下載_JDK6官方下載地址:http://www.java.net/download/jdk6/6u10/promoted/b32/binaries/jdk-6u10-rc2-bin-b32-windows-i586-p-12_sep_2008.exe

    JDK6 API CHM中文參考下載:

    JDK6API中文參考070114.rar : http://chinesedocument.com/upimg/soft/JDK6API中文參考070114.rar

    Java SE 6 API 中文版 CHM 下載:http://download.java.net/jdk/jdk-api-localizations/jdk-api-zh-cn/publish/1.6.0/chm/JDK_API_1_6_zh_CN.CHM

    Java SE 5 API 中文版 CHM 下載:http://download.java.net/jdk/jdk-api-localizations/jdk-api-zh-cn/builds/JDK_API_1_5_zh_CN.CHM

    JDK6 API 中文版下載:

    posted @ 2008-10-17 13:53 華夢(mèng)行 閱讀(778) | 評(píng)論 (1)編輯 收藏
    ?由于常常要和漢字處理打交道,因此,我常常受到漢字編碼問題的困擾。在不斷的打擊與堅(jiān)持中,也積累了一點(diǎn)漢字編碼方面的經(jīng)驗(yàn),想和大家一起分享。

    一、漢字編碼的種類

    ??? 漢字編碼中現(xiàn)在主要用到的有三類,包括GBKGB2312Big5

    ??? 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 GBKGB2312的擴(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ì)于GB2312GBK可用下面兩個(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é)從0xA00xFE,低字節(jié)從0x400x7E,和0xA10xFE兩部分。判斷一個(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)在主要用到的有三類,包括GBKGB2312Big5

    ??? 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 GBKGB2312的擴(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ì)于GB2312GBK可用下面兩個(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é)從0xA00xFE,低字節(jié)從0x400x7E,和0xA10xFE兩部分。判斷一個(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)編輯 收藏
    僅列出標(biāo)題
    共15頁(yè): First 上一頁(yè) 2 3 4 5 6 7 8 9 10 下一頁(yè) Last 
    主站蜘蛛池模板: 污污视频免费观看网站| JLZZJLZZ亚洲乱熟无码| 亚洲日韩精品无码AV海量| 100000免费啪啪18免进| 亚洲国产精品成人综合色在线婷婷| 国产精品白浆在线观看免费 | 3d动漫精品啪啪一区二区免费| 亚洲精品无码午夜福利中文字幕| 香蕉视频在线免费看| 亚洲日本一区二区三区在线| 最新亚洲成av人免费看| 亚洲成a人片在线观看无码专区| 国产成人AV片无码免费| 亚洲成人在线网站| 亚洲免费网站在线观看| 亚洲三级视频在线观看| 成年女人18级毛片毛片免费观看| 亚洲色大成网站www永久男同| 韩国日本好看电影免费看| 羞羞视频网站免费入口| 亚洲精品综合久久| 你是我的城池营垒免费看| 久久久久无码精品亚洲日韩| 人妻无码一区二区三区免费| 亚洲免费视频播放| 成年私人影院免费视频网站| 亚洲第一综合天堂另类专| 免费一级毛片一级毛片aa| 国产97视频人人做人人爱免费| 亚洲精品无码久久久影院相关影片| 日韩免费电影网址| 国产成人精品日本亚洲专| 日韩高清在线免费观看| 深夜久久AAAAA级毛片免费看| 亚洲无人区一区二区三区| 99爱视频99爱在线观看免费| 亚洲冬月枫中文字幕在线看 | 日本在线高清免费爱做网站| 亚洲日韩精品无码AV海量| 免费在线观看a级毛片| 97超高清在线观看免费视频|