JAVA如何正确处理Unicode字符
最近在開發(fā)輸入法程序時遇到一個小問題,就是刪除一個emoji時,不能一次刪干凈,需要執(zhí)行兩次操作才可以。Intuitively,這肯定是java操作unicode字符的問題,于是找了JAVA官方文檔參考一下,解決了這個問題,這里做下簡單總結(jié)。原文在這里,有興趣自己看。
http://www.oracle.com/technetwork/articles/java/supplementary-142654.html
注:文章中提到的“JAVA字節(jié)”均指JAVA平臺的16位字節(jié),請不要和C的8位字節(jié)搞混。
首先需要知道標準Unicode字符是一個16位字符(廢話),所以標準Unicode字符集包含65536個字符(2的16次方嘛,哥的數(shù)學(xué)很好的)。但是僅僅65536個字符是遠遠不夠用的,尤其是為了包含我們偉大中華民族豐富多彩的文字(反正我是不認識),Unicode字符集進行了擴展,擴展到了24位,也就是最多可以包含1,112,064個字符。這里我們把標準Unicode字符集(也就是前65536個字符)叫做Basic Multilingual Plane (BMP),把超過16位以上的擴展字符集叫做supplementary characters。
UTF-16是一種編碼方式,以16位無符號單元來編碼Unicode字符,如果對一個標準Unicode字符編碼,只需要占用一個UTF-16單元,如果對擴展Unicode字符編碼則需要占用兩個UTF-16單元。
我們都知道在C語言中,一個primitive char占用一個字節(jié),也就是8位。但是在JAVA中,一個primitive char占用16位,與一個標準Unicode字符長度相等,因為JAVA平臺采用UTF-16進行編碼。這樣JAVA就很容易處理Unicode基本字符。但是對于Unicode的擴展字符,在JAVA中就需要占用兩個char,也就是兩個UTF-16單元。
舉個栗子,大寫字母A的Unicode值為U+0041,它屬于Unicode的基本字符集,所以它只占用一個UTF-16單元,表示為[0041]。而字符的Unicode值為U+10400,它屬于擴展Unicode字符集,所以它占用兩個UTF-16編碼單元,表示為[D801][DC00](一個中括號代表一個UTF-16單元,中括號本身沒意義)。第一個單元叫做high-surrogates,范圍從?U+D800 到 U+DBFF,第二個單元叫l(wèi)ow-surrogates,范圍從 U+DC00 到 U+DFFF,這個看起來很類似多字節(jié)編碼。但是,我說的是但是,這里有一個非常重要的不同點,從U+D800 到 U+DFFF 其實為UTF-16的保留值范圍,專門用作編碼Unicode擴展字符集,這個范圍不被賦予任何實際的標準Unicode字符。也就是說,在你的程序里只要判斷一個字符是否屬于這個范圍內(nèi),就可以知道這個字符是應(yīng)該被當(dāng)做一個獨立的Unicode基本字符處理,還是當(dāng)做半個擴展Unicode字符。
回到我一開始提到問題,我在開發(fā)android輸入法的時候,當(dāng)需要刪除一個emoji時,總是需要刪除兩次才能刪干凈。這是因為我用的emoji都是屬于Unicode擴展字符集的,在編輯框中占用了兩個UTF-16單元,而每執(zhí)行一次刪除操作只刪除了一個UTF-16單元,也就是一個JAVA字節(jié),而另一個單元沒有被刪除,所以就會顯示異常。這時候只要再刪除掉另一個字節(jié)就算真正把這個emoji刪除干凈了。
用戶在實際的應(yīng)用中,肯定是把Unicode標準字符集和擴展字符集混合著使用,也就是說有的字符占用1個java字節(jié),有的字符占用兩個java字節(jié)。那么我在執(zhí)行刪除一個字符的操作時必須也要先去判斷我是要一次性刪除一個字節(jié)還是刪除兩個字節(jié)。這就很簡單了,按照我前面提到的規(guī)則,先判斷一下被操作的字符值是否處于[U+D800,U+DFFF](inclusive)之間,如果是,就說明被操作的字符不是一個有效的標準Unicode字符,而是半個Unicode擴展字符,那么只需要在程序中自動刪除兩個java字節(jié)就可以了。反之,如果被處理的字符不屬于[U+D800,U+DFFF]范圍內(nèi),那么這個字符就是一個標準的Unicode字符,只需要按照一個java字節(jié)處理就可以了。
理論清楚后(我假設(shè)你清楚了,其實也不難,就是我表達的不清楚,沒辦法,工科人,總是思維超越語言),我再簡單介紹一下java中相關(guān)的處理函數(shù)。
Character.toChars(int?codePoint):參數(shù)codePoint為Unicode值,此函數(shù)將Unicode值轉(zhuǎn)換為標準java字節(jié)數(shù)組。如果codePoint是Unicode標準字符,則返回值只包含一個char;如果codePoint是擴展Unicode字符,則返回值包含2個char。
例:在程序中如果要輸出一個Unicode擴展字符,可以這樣String.valueOf(Character.toChars(0x1F60E))
Character.isLowSurrogate(char?ch):判斷一個字符是否是一個Unicode擴展字符的低16位編碼。
Character.isHighSurrogate(char?ch):判斷一個字符是否是一個Unicode擴展字符的高16位編碼。
轉(zhuǎn)載于:https://blog.51cto.com/yaorugang/1704142
總結(jié)
以上是生活随笔為你收集整理的JAVA如何正确处理Unicode字符的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ICE相关链接
- 下一篇: fgui的ui管理框架_ET框架FGUI