摘要:本文從Unicode入手,介紹由于通信問題而產(chǎn)生的字符集糜芳,以及Unicode的發(fā)展情況飒货。介紹各種字符集的及其使用。并適時(shí)的介紹一些歷史情況峭竣,主要討論字符集在java及C語言環(huán)境中的使用塘辅,及闡述UTF,ISO 8859-1皆撩,ASCII他們之間的關(guān)系扣墩。會(huì)介紹一些亂碼知識(shí),總而言之扛吞,亂碼產(chǎn)生的根本原因就是:編碼與解碼不一致造成的呻惕。
一、概念:
1滥比、BCD碼
最初的計(jì)算機(jī)性能和存儲(chǔ)容量都比較差亚脆,所以普遍采用4位BCD(BinaryCoded Decimal)編碼(這個(gè)編碼出現(xiàn)比計(jì)算機(jī)還早,最早是用在打孔卡上的)盲泛。BCD編碼簡(jiǎn)單點(diǎn)說就是將十進(jìn)制數(shù)用二進(jìn)制表示濒持,如下圖所示。
十進(jìn)制數(shù) | 8421BCD編碼 |
---|---|
0 | 0000 |
1 | 0001 |
2 | 0010 |
3 | 0011 |
4 | 0100 |
5 | 0101 |
6 | 0110 |
7 | 0111 |
8 | 1000 |
9 | 1001 |
BCD編碼表示數(shù)字還可以寺滚,但表示字母或符號(hào)就很不好用柑营,需要用多個(gè)編碼來表示。后來經(jīng)過演變發(fā)展成了ASCII碼村视。ASCII含33(ASCII碼范圍為:0~31和127)個(gè)控制字符官套, 和95(ASCII碼范圍32~126)個(gè)可顯示字符。
2蚁孔、由ASCII碼發(fā)展到Unicode
ASCII編碼存儲(chǔ)方式:
其中最高位0奶赔,其余七位為0或1,可表示的范圍為:0 ~ 2^7= 0 ~ 128
C語言實(shí)現(xiàn)打印字符A
# include <stdio.h>
int main()
{
char ch = '65';
printf("%c", ch);
return 0;
}
下圖為ASCII碼表
后來勒虾,就像建造巴比倫塔一樣纺阔,世界各地的都開始使用計(jì)算機(jī)瘸彤,但是很多國家用的不是英文修然,他們的字母里有許多是ASCII里沒有的,為了可以在計(jì)算機(jī)保存他們的文字,他們決定采用127號(hào)之后的空位來表示這些新的字母愕宋、符號(hào)玻靡,還加入了很多畫表格時(shí)需要用下到的橫線、豎線中贝、交叉等形狀囤捻,一直把序號(hào)編到了最后一個(gè)狀態(tài)255。從128到255這一頁的字符集被稱"擴(kuò)展字符集"邻寿。從此之后蝎土,貪婪的人類再?zèng)]有新的狀態(tài)可以用了。
等中國人們得到計(jì)算機(jī)時(shí)绣否,已經(jīng)沒有可以利用的字節(jié)狀態(tài)來表示漢字誊涯,況且有6000多個(gè)常用漢字需要保存呢。但是這難不倒智慧的中國人民蒜撮,我們不客氣地把那些127號(hào)之后的奇異符號(hào)們直接取消掉, 規(guī)定:一個(gè)小于127的字符的意義與原來相同暴构,但兩個(gè)大于127的字符連在一起時(shí),就表示一個(gè)漢字段磨,前面的一個(gè)字節(jié)(他稱之為高字節(jié))從0xA1用到0xF7取逾,后面一個(gè)字節(jié)(低字節(jié))從0xA1到0xFE,這樣我們就可以組合出大約7000多個(gè)簡(jiǎn)體漢字了苹支。在這些編碼里砾隅,我們還把數(shù)學(xué)符號(hào)、羅馬希臘的字母债蜜、日文的假名們都編進(jìn)去了琉用,連在 ASCII 里本來就有的數(shù)字、標(biāo)點(diǎn)策幼、字母都統(tǒng)統(tǒng)重新編了兩個(gè)字節(jié)長(zhǎng)的編碼邑时,這就是常說的"全角"字符,而原來在127號(hào)以下的那些就叫"半角"字符了特姐。
中國人民看到這樣很不錯(cuò)晶丘,于是就把這種漢字方案叫做"GB2312"。GB2312
是對(duì)ASCII
的中文擴(kuò)展唐含。
但是中國的漢字太多了浅浮,我們很快就就發(fā)現(xiàn)有許多人的人名沒有辦法在這里打出來,特別是某些很會(huì)麻煩別人的國家領(lǐng)導(dǎo)人捷枯。于是我們不得不繼續(xù)把 GB2312
沒有用到的代碼點(diǎn)找出來老實(shí)不客氣地用上滚秩。
后來還是不夠用,于是干脆不再要求低字節(jié)一定是127號(hào)之后的內(nèi)碼淮捆,只要第一個(gè)字節(jié)是大于127就固定表示這是一個(gè)漢字的開始郁油,不管后面跟的是不是擴(kuò)展字符集里的內(nèi)容本股。結(jié)果擴(kuò)展之后的編碼方案被稱為 GBK
標(biāo)準(zhǔn),GBK
包括了GB2312
的所有內(nèi)容桐腌,同時(shí)又增加了近20000個(gè)新的漢字(包括繁體字)和符號(hào)拄显。后來少數(shù)民族也要用電腦了,于是我們?cè)贁U(kuò)展案站,又加了幾千個(gè)新的少數(shù)民族的字躬审,GBK
擴(kuò)成了 GB18030
。從此之后蟆盐,中華民族的文化就可以在計(jì)算機(jī)時(shí)代中傳承了承边。
由于世界各地都產(chǎn)生了自己的編碼方案,這是給人的溝通帶來了巨大麻煩石挂。于是有一個(gè)叫做ISO的國際組織開始著手解決這個(gè)問題炒刁,想用一種規(guī)范來表示出所有的語言。于是Unicode就這樣產(chǎn)生了誊稚。注意:Unicode是內(nèi)存編碼表示方案(是規(guī)范)翔始,而UTF是如何保存和傳輸U(kuò)nicode的方案(是實(shí)現(xiàn))這也是UTF與Unicode的區(qū)別。
字符是各種文字和符號(hào)的總稱里伯,包括各個(gè)國家文字城瞎、標(biāo)點(diǎn)符號(hào)、圖形符號(hào)疾瓮、數(shù)字等脖镀。字符集是多個(gè)字符的集合,字符集種類較多狼电,每個(gè)字符集包含的字符個(gè)數(shù)不同蜒灰,常見字符集有:ASCII字符集、ISO 8859字符集肩碟、GB2312字符集强窖、BIG5字符集、GB18030字符集削祈、Unicode字符集等翅溺。
各個(gè)國家和地區(qū)在制定編碼標(biāo)準(zhǔn)的時(shí)候,“字符的集合”和“編碼”一般都是同時(shí)制定的髓抑。因此咙崎,平常我們所說的“字符集”,比如:GB2312, GBK, JIS 等吨拍,除了有“字符的集合”這層含義外褪猛,同時(shí)也包含了“編碼”的含義。
3羹饰、ISO 8859-1
ISO/IEC8859-1
伊滋,又稱Latin-1
或“西歐語言”碳却,是國際標(biāo)準(zhǔn)化組織內(nèi)ISO/IEC 885
9的第一個(gè)8位字符集。它以ASCII為基礎(chǔ)新啼,在空置的0xA0-0xFF的范圍內(nèi),加入96個(gè)字母及符號(hào)刹碾,藉以供使用變音符號(hào)的拉丁字母語言使用燥撞。iOS 8859-1
表示的字符就是Unicode的0x0000-0x00ff
之間的字符。
在下文代碼頁中有關(guān)于ISO 8859-1與Windows-1252的區(qū)別迷帜。
4物舒、Unicode編碼詳解
Unicode字符集可以簡(jiǎn)寫為UCS(Unicode Character Set),0x0000~0X00ff與ISO 8859-1保持一致
Unicode可以邏輯分為17平面(Plane)戏锹,每個(gè)平面擁有65536( = 2^16)個(gè)代碼點(diǎn)冠胯,雖然目前只有少數(shù)平面被使用。
平面0 (0000–FFFF): 基本多文種平面(Basic Multilingual Plane, BMP).
平面1 (10000–1FFFF): 多文種補(bǔ)充平面(SupplementaryMultilingual Plane, SMP).
平面2 (20000–2FFFF): 表意文字補(bǔ)充平面(SupplementaryIdeographic Plane, SIP).
平面3 (30000–3FFFF): 表意文字第三平面(TertiaryIdeographic Plane, TIP).
平面4 to 13 (40000–DFFFF)尚未使用
平面14 (E0000–EFFFF): 特別用途補(bǔ)充平面(SupplementarySpecial-purpose Plane, SSP)
平面15 (F0000–FFFFF)保留作為私人使用區(qū)(PrivateUse Area, PUA)平面16 (100000–10FFFF)锦针,保留作為私人使用區(qū)(PrivateUse Area, PUA)
中荠察、日、韓的三種文字占用了Unicode中0x3000(12288)到0x9FFF(40959)的部分奈搜,共計(jì)28671個(gè)字符悉盆;
而中文在BMP中的范圍是:U+4E00到U+9FA5之間是漢字的Unicode編碼。
5馋吗、 UTF格式詳解
UTF
是 Unicode Transformation Format
的縮寫焕盟。是Unicode的一種實(shí)現(xiàn)方案。任何文字在Unicode中都對(duì)應(yīng)一個(gè)值宏粤,這個(gè)值稱為代碼點(diǎn)也叫碼位(CodePoint)脚翘。代碼點(diǎn)的值通常寫為:U+ABCD,在Java中可以直接將一個(gè)字符賦值為
public class Test1 {
public static void main(String[] args) throws Exception {
char ch = '\u6211';
System.out.println(ch);
}
}
輸出結(jié)果:我
UTF-8四種具體實(shí)現(xiàn)方式:
1.第一種是一個(gè)字節(jié)的編碼:即128個(gè)ascii字符(只需要一個(gè)字節(jié))
格式:0xxxxxxx
2^7 - 1 = 127 = 7F = (0111-1111)
編碼方式Unicoe范圍由(U+0000 至 U+007F)
**2.第二種是兩個(gè)字節(jié)的編碼:即帶有符號(hào)的拉丁文绍哎,希臘文来农,西里爾字母,亞美尼亞語崇堰,希伯來文备图,阿拉伯文等,則需要兩個(gè)字節(jié)編碼(Unicode 范圍由U+0080至U+07FF) **
格式:110xxxxx 10xxxxxx
(0080)16 = (128)10
(07FF) 16 = (2047)10 = 2^11-1;
3.第三種是三字節(jié)的編碼赶袄,即其他多文種平面(BMP)中的字符(這包括了大部分的漢字)(范圍為: U+0800 至 U+FFFF)
格式:1110xxxx 10xxxxxx 10xxxxxx
U+0800 = 2048揽涮;
U+FFFF = 65535 = 2^16 -1;
1110xxxx 10xxxxxx 10xxxxxx
4.第四種是4-6字節(jié)編碼饿肺。
U+1 0000至U+1 FFFFF:使用四字節(jié)
U+20 0000 至U+3FF FFFF:使用五字節(jié)
U+400 0000至U+7FFF FFFF
例如“漢”字的Unicode編碼是6C49蒋困。6C49在0800-FFFF之間,所以肯定要用3字節(jié)模板了:1110xxxx 10xxxxxx 10xxxxxx敬辣。將6C49寫成二進(jìn)制是:0110 110001 001001雪标, 用這個(gè)比特流依次代替模板中的x零院,得到:11100110 10110001 10001001,即E6 B1 89村刨。
目前計(jì)算機(jī)一般使用 2 個(gè)字節(jié)(16 位)來存放一個(gè)序號(hào)(DBCS,DoubleByte Character System)告抄,因此,這種方式存放的字符也被稱作寬字節(jié)字符嵌牺。比如打洼,字符串"中文123" 在 Windows2000 下,內(nèi)存中實(shí)際存放的是 5 個(gè)字符逆粹,一共10個(gè)字節(jié)募疮;若在gb2312編碼中,共計(jì)五個(gè)字符僻弹,7個(gè)字節(jié)阿浓。
UTF-16和UCS-2區(qū)別與聯(lián)系
UTF-16和UCS-2都是Unicode的編碼方式。
Unicode使用一個(gè)確定的名字和一個(gè)叫做碼位(code point)的整數(shù)來定義一個(gè)字符蹋绽。例如?字符被命名為“copyright sign”并且有一個(gè)值為U+00A9(0xA9芭毙,十進(jìn)制169)的碼位。
Unicode的碼空間從U+0000到U+10FFFF卸耘,共有1,112,064個(gè)碼位(code point)可用來映射字符. Unicode的碼空間可以劃分為17個(gè)平面(plane)稿蹲,每個(gè)平面包含216
(65,536)個(gè)碼位。每個(gè)平面的碼位可表示為從U+xx0000到U+xxFFFF, 其中xx表示十六進(jìn)制值從0016
到1016
鹊奖,共計(jì)17個(gè)平面苛聘。
第一個(gè)Unicode平面(碼位從U+0000至U+FFFF)包含了最常用的字符,該平面被稱為基本多語言平面(Basic Multilingual Plane)忠聚,縮寫為BMP设哗。其他平面稱為輔助平面(Supplementary Planes)。
UCS-2 (2-byte Universal Character Set)是一種定長(zhǎng)的編碼方式两蟀,UCS-2僅僅簡(jiǎn)單的使用一個(gè)16位碼元來表示碼位网梢,也就是說在0到0xFFFF的碼位范圍內(nèi),它和UTF-16基本一致赂毯。
UTF-16 (16-bit Unicode Transformation Format)是UCS-2的拓展战虏,它可以表示BMP以為的字符。UTF-16使用一個(gè)或者兩個(gè)16位的碼元來表示碼位党涕,這樣就可以對(duì)0到0x10FFFF的碼位進(jìn)行編碼烦感。
例如,在UCS-2和UTF-16中膛堤,BMP中的字符U+00A9 copyright sign(?)都被編碼為0x00A9手趣。
但是在BMP之外的字符,例如??肥荔,只能用UTF-16進(jìn)行編碼绿渣,使用兩個(gè)16為碼元來表示:0xD834 0xDF06朝群。這被稱作代理對(duì),值得注意的是一個(gè)代理對(duì)僅僅表示一個(gè)字符中符,而不是兩個(gè)姜胖。UCS-2并沒有代理對(duì)的概念,所以會(huì)將0xD834 0xDF06解釋為兩個(gè)字符淀散。
簡(jiǎn)單的說右莱,UTF-16可看成是UCS-2的父集。在沒有輔助平面字符(surrogate code points)前吧凉,UTF-16與UCS-2所指的是同一的意思隧出。(嚴(yán)格的說這并不正確踏志,因?yàn)樵赨TF-16中從U+D800到U+DFFF的碼位不對(duì)應(yīng)于任何字符阀捅,而在使用UCS-2的時(shí)代,U+D800到U+DFFF內(nèi)的值被占用针余。)但當(dāng)引入輔助平面字符后饲鄙,就稱為UTF-16了。
6圆雁、代碼頁及字符集對(duì)照表
Windows將字符集稱作代碼頁忍级。代碼頁是字符集編碼的別名,也有人稱"內(nèi)碼表",
代碼頁 | 名稱 | 顯示名稱 |
---|---|---|
37 | IBM037 | IBM EBCDIC(美國 - 加拿大) |
936 | gb2312 | 簡(jiǎn)體中文 (GB2312) |
950 | big5 | 繁體中文 (Big5) |
1200 | utf-16 | Unicode(Little-Endian) |
1201 | UnicodeFFFE | Unicode (Big-Endian) |
28591 | Windows-28591 | ISO-8859-1 |
65001 | UTF-8 | UTF-8 |
7伪朽、ISO-8859-1和Windows-1252的區(qū)別
ISO-8859-1轴咱,正式編號(hào)為ISO/IEC 8859-1:1998,又稱Latin-1或“西歐語言”烈涮,是國際標(biāo)準(zhǔn)化組織內(nèi)ISO/IEC 8859的第一個(gè)8位字符集朴肺。它以ASCII為基礎(chǔ),在空置的0xA0-0xFF的范圍內(nèi)坚洽,加入96個(gè)字母及符號(hào)戈稿,藉以供使用附加符號(hào)的拉丁字母語言使用。Unicode的前0-255個(gè)字符與ISO-8859-1相一致讶舰。
Windows-1252經(jīng)常被錯(cuò)誤地貼上ISO-8859-1的標(biāo)簽鞍盗,因?yàn)樗鼈兪窒嗨啤3?28到159(十六進(jìn)制80到9F)范圍內(nèi)的很少使用的C1控制字符被替換為額外的字符外跳昼,Windows-1252代碼頁的字符和ISO-8859-1完全一致般甲。Windows-28591代碼頁才是真正的ISO-8859-1,然而鹅颊,英文版的Windows 7系統(tǒng)上似乎沒有Windows-28591代碼頁欣除,至于其他系統(tǒng)有沒有我就不知道了。Windows-1252是ISO的超集挪略。
UTF-16與UCS-2的聯(lián)系與區(qū)別:
UTF-16和UCS-2都是Unicode的編碼方式历帚。Unicode使用一個(gè)確定的名字和一個(gè)叫做代碼點(diǎn)(code point)的整數(shù)來定義一個(gè)字符滔岳。例如?字符被命名為“copyright sign”并且有一個(gè)值為U+00A9(0xA9,十進(jìn)制169)的代碼點(diǎn)挽牢。
Unicode的碼空間為U+0000到U+10FFFF谱煤,共有1,112,064個(gè)代碼點(diǎn)(code point)可用來映射字符. Unicode的碼空間可以劃分為17個(gè)平面(plane),每個(gè)平面包含216(65,536)個(gè)代碼點(diǎn)禽拔。每個(gè)平面的代碼點(diǎn)可表示為從U+xx0000到U+xxFFFF, 其中xx表示十六進(jìn)制值從0016 到1016刘离,共計(jì)17個(gè)平面。
第一個(gè)Unicode平面(代碼點(diǎn)從U+0000至U+FFFF)包含了最常用的字符睹栖,該平面被稱為基本多語言平面(Basic Multilingual Plane)硫惕,縮寫為BMP。其他平面稱為輔助平面(Supplementary Planes)野来。
UCS-2 (2-byte UniversalCharacter Set)是一種定長(zhǎng)的編碼方式恼除,UCS-2僅僅簡(jiǎn)的使用一個(gè)16位碼元來表示代碼點(diǎn),也就是說在0到0xFFFF的代碼點(diǎn)范圍內(nèi)曼氛,它和UTF-16基本一致豁辉。
UTF-16 (16-bit UnicodeTransformation Format)是UCS-2的拓展,它可以表示BMP以為的字符舀患。UTF-16使用一個(gè)或者兩個(gè)16位的碼元來表示代碼點(diǎn)徽级,這樣就可以對(duì)0到0x10FFFF的代碼點(diǎn)進(jìn)行編碼。
例如聊浅,在UCS-2和UTF-16中餐抢,BMP中的字符U+00A9copyright sign(?)都被編碼為0x00A9。
但是在BMP之外的字符低匙,例如旷痕,只能用UTF-16進(jìn)行編碼,使用兩個(gè)16位碼元來表示:0xD834 0xDF06努咐。這被稱作代理對(duì)苦蒿,值得注意的是一個(gè)代理對(duì)僅僅表示一個(gè)字符,而不是兩個(gè)渗稍。UCS-2并沒有代理對(duì)的概念佩迟,所以會(huì)將0xD834 0xDF06解釋為兩個(gè)字符。
簡(jiǎn)單的說竿屹,UTF-16可看成是UCS-2的父集报强。在沒有輔助平面字符(surrogate code points)前,UTF-16與UCS-2所指的是同一的意思拱燃。(嚴(yán)格的說這并不正確秉溉,因?yàn)樵赨TF-16中從U+D800到U+DFFF的代碼點(diǎn)不對(duì)應(yīng)于任何字符,而在使用UCS-2的時(shí)代,U+D800到U+DFFF內(nèi)的值被占用召嘶。)但當(dāng)引入輔助平面字符后父晶,就稱為UTF-16了。
但UCS-2只是一個(gè)編碼方案弄跌,UTF-16卻要用于實(shí)際的傳輸甲喝,所以就不得不考慮字節(jié)序的問題。
8铛只、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是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 WIDTHNO-BREAK SPACE"握牧。
這樣如果接收者收到FEFF容诬,就表明這個(gè)字節(jié)流是Big-Endian的;如果收到FFFE沿腰,就表明這個(gè)字節(jié)流是Little-Endian的览徒。因此字符" zero widthno-break space"又被稱作BOM。
UTF-8不需要BOM來表明字節(jié)順序颂龙,但可以用BOM來表明編碼方式习蓬。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8編碼是EF BB BF(讀者可以用我們前面介紹的編碼方法驗(yàn)證一下)。所以如果接收者收到以EF BB BF開頭的字節(jié)流措嵌,就知道這是UTF-8編碼了躲叼。
9、Windows記事本有四種保存格式
用記事本-文件-另存為企巢,如上如圖即可看到Windows記事本保存的四種格式枫慷,如上如所示,分別為:
ANSI:在簡(jiǎn)體中文系統(tǒng)的windows中ANSI即gb2312.
Unicode:對(duì)應(yīng)UTF-16LE,
Unicode Big Endian:對(duì)應(yīng)UTF-16BE
UTF-8:使用了變長(zhǎng)的編碼
Big Endian 和 Little Endian名詞的由來
這兩個(gè)術(shù)語來自于 Jonathan Swift 的《《格利佛游記》其中交戰(zhàn)的兩個(gè)派別無法就應(yīng)該從哪一端--小端還是大端--打開一個(gè)半熟的雞蛋達(dá)成一致或听。:)
“endian”這個(gè)詞出自《格列佛游記》探孝。小人國的內(nèi)戰(zhàn)就源于吃雞蛋時(shí)是究竟從大頭(Big-Endian)敲開還是從小頭(Little-Endian)敲開,由此曾發(fā)生過六次叛亂誉裆,其中一個(gè)皇帝送了命再姑,另一個(gè)丟了王位。
我們一般將endian翻譯成“字節(jié)序”找御,將big endian和little endian稱作“大尾”和“小尾”元镀。
在那個(gè)時(shí)代,Swift是在諷刺英國和法國之間的持續(xù)沖突霎桅,Danny Cohen栖疑,一位網(wǎng)絡(luò)協(xié)議的早期開創(chuàng)者,第一次使用這兩個(gè)術(shù)語來指代字節(jié)順序滔驶,后來這個(gè)術(shù)語被廣泛接納了遇革。
主要表現(xiàn)在存儲(chǔ)格式上,比如一個(gè)字符的編碼為ABCD
Big Endian的(FE FF)存儲(chǔ)格式為:AB CD揭糕;
Little Endian的(FF FE)存儲(chǔ)格式為:CD AB 萝快;
Windows記事本就是使用BOM來標(biāo)記文本文件的編碼方式的。當(dāng)打開一個(gè)txt文本著角,會(huì)自動(dòng)添加BOM揪漩。
二 應(yīng)用
- 1 Java對(duì)字符的處理
1 )、String類的public byte[] getBytes(Charset charset)
這是java字符串處理的一個(gè)標(biāo)準(zhǔn)函數(shù)吏口,其作用是將字符串所表示的字符按照charset編碼奄容,并以字節(jié)方式表示。注意字符串在java內(nèi)存中總是按unicode編碼存儲(chǔ)的产徊。
public class Test1 {
public static void main(String[] args) throws Exception {
String string = "你好昂勒!";
String str1 = new String(string.getBytes("gbk"));
System.out.println(str1);
}
}
將一個(gè)String 類型Unicode字符串轉(zhuǎn)為對(duì)應(yīng)字節(jié),一般String默認(rèn)光標(biāo)gbk編碼舟铜;各個(gè)編譯器可能不同戈盈,可以到windows-preference-general-workspace界面的左下角有顯示,也可以自行調(diào)節(jié)谆刨。
2)塘娶、 new String(charset)
這是java字符串處理的另一個(gè)標(biāo)準(zhǔn)函數(shù),和上一個(gè)函數(shù)的作用相反痴荐,將字節(jié)數(shù)組按照charset編碼進(jìn)行組合識(shí)別血柳,最后轉(zhuǎn)換為unicode存儲(chǔ)。參考上述getBytes的例子
3)生兆、setCharacterEncoding()
該函數(shù)用來設(shè)置http請(qǐng)求或者相應(yīng)的編碼难捌。
1.2. String 與byte的相互轉(zhuǎn)換
java字符編碼常見問題主要在兩個(gè)方面
- 字節(jié)到String
- String轉(zhuǎn)字節(jié)膝宁。
1.2.1 字節(jié)到String。
只有字節(jié)才有編碼含義根吁,String永遠(yuǎn)是Unicode员淫。在java中,字符默認(rèn)存儲(chǔ)的編碼為utf-8碼击敌,所以String str1 = “你好介返,Ice Blue”;Str的編碼為utf-8可以用一下代碼來實(shí)驗(yàn):
System.out.println(Charset.defaultCharset());
以下java代碼實(shí)現(xiàn)了將一個(gè)字符的編碼轉(zhuǎn)換為漢字。
public class Test02 {
public static void main(String[] args) throws Exception {
System.out.println("字節(jié)按編碼轉(zhuǎn)成字符:");
String strUtf8Hex = "E4B8ADE69687"; // “中文”的utf8的16進(jìn)制編碼
byte byteUtf8[] = hex2byte(strUtf8Hex);// 轉(zhuǎn)成字節(jié)流
String str = new String(byteUtf8,"UTF-8");
System.out.println(str);
}
public static byte[] hex2byte(String str) {
byte[] b = new byte[str.length() / 2];
for (inti = 0; i < str.length(); i += 2) {
String str2 = str.substring(i, i + 2);
b[i / 2] = (byte) Integer.parseInt(str2, 16);
}
return b;
}
}
2. String轉(zhuǎn)字節(jié)沃斤。String.getBytes方法是按編碼集轉(zhuǎn)換編碼圣蝎,不能理解為取出String的字節(jié)來。是平時(shí)常見轉(zhuǎn)碼工作應(yīng)該采用的方法衡瓶。
以下代碼實(shí)現(xiàn)了將一個(gè)漢字轉(zhuǎn)換為其對(duì)應(yīng)編碼
public class Test1 {
public static void main(String[]args) throws Exception {
System.out.println("字節(jié)按編碼轉(zhuǎn)成字符:");
String strUtf8Hex ="中文賦";// “中文”的utf8的16進(jìn)制編碼
byte[] Utf8byte = strUtf8Hex.getBytes("UTF-16BE");
System.out.println(byte2hex(Utf8byte));
}
public static String byte2hex(byte[]b) {
String sum = "";
String stmp = "";
for (inti = 0; i < b.length; i++) {
stmp = Integer.toHexString(b[i] & 0XFF);//保留前8位
if (stmp.length() == 1)
sum = sum + "0" + stmp;
else
sum = sum + stmp;
}
return sum.toUpperCase();
}
}
拓展:
計(jì)算機(jī)數(shù)制的概念
基本概念:
數(shù)碼:數(shù)制中表示基本數(shù)值大小的不同數(shù)字符號(hào)徘公。
例如,
二進(jìn)制有兩個(gè)數(shù)碼:0,1哮针;
十進(jìn)制有10個(gè)數(shù)碼:0关面、1、2十厢、3等太、4、5蛮放、6缩抡、7、8筛武、9缝其。
十六進(jìn)制有16個(gè)數(shù)碼:0挎塌、1徘六、2、3榴都、4待锈、5、6嘴高、7竿音、8、9拴驮,A春瞬、B、C套啤、D宽气、E、F
基數(shù):數(shù)制所使用數(shù)碼的個(gè)數(shù)。例如萄涯,二進(jìn)制的基數(shù)為2绪氛;十進(jìn)制的基數(shù)為10。****
位權(quán): 數(shù)制中某一位上的1所表示數(shù)值的大欣杂啊(所處位置的價(jià)值)枣察。例如,十進(jìn)制的123燃逻,1的位權(quán)是100序目,2的位權(quán)是10,3的位權(quán)是1伯襟。二進(jìn)制中的 1011 宛琅,第一個(gè)1的位權(quán)是8,0的位權(quán)是4逗旁,第二個(gè)1的位權(quán)是2嘿辟,第三個(gè)1的位權(quán)是1;
數(shù)制:按進(jìn)位的原則進(jìn)行計(jì)數(shù)片效,稱為進(jìn)位計(jì)數(shù)制红伦,簡(jiǎn)稱數(shù)制。不論是哪一種數(shù)制淀衣,其計(jì)數(shù)和運(yùn)算都有共同的規(guī)律和特點(diǎn)昙读。
⑴ ** 逢N進(jìn)一
N是指數(shù)制中所需要的數(shù)字字符的總個(gè)數(shù),稱為基數(shù)膨桥。如:0蛮浑、1、2只嚣、3沮稚、4、5册舞、6蕴掏、7、8调鲸、9等10個(gè)不同的符號(hào)來表示數(shù)值盛杰,這個(gè)10就是數(shù)字字符的總個(gè)數(shù),也是十進(jìn)制的基數(shù)藐石,表示逢十進(jìn)一即供。
⑵ ** 位權(quán)表示法
位權(quán)是指一個(gè)數(shù)字在某個(gè)固定位置上所代表的值,處在不同位置上的數(shù)字所代表的值不同于微,每個(gè)數(shù)字的位置決定了它的值或者位權(quán)逗嫡。位權(quán)與基數(shù)的關(guān)系是:各進(jìn)位制中位權(quán)的值是基數(shù)的若干次冪办素。
數(shù)制符號(hào)
二進(jìn)制B(binary)
八進(jìn)制O(octal)
十進(jìn)制D(decimal)
十六進(jìn)制H(hexadecimal)
至于進(jìn)制轉(zhuǎn)換網(wǎng)上有很多參考文檔,這里不再贅述祸穷。
參考資料:
[1] 趣談Unicode性穿,ansi,utf-8,Unicode big endian這些編碼有什么區(qū)別(http://blog.csdn.net/fanwenbo/article/details/2298800)
[2] Unicode字符查詢(http://unicode-table.com/cn/#control-character)
[3] 國標(biāo)碼查詢 (http://www.qqxiuzi.cn/bianma/guobiaoma.php)
[4] Code Page Identifiers ( https://msdn.microsoft.com/en-us/library/windows/desktop/dd317756(v=vs.85).aspx)
[5] UTF-16與UCS-2的區(qū)別 http://demon.tw/programming/utf-16-ucs-2.html