中文字符與編碼格式佔位問題

最近面試,碰到的面試題。面試

Q:中文字符在UTF-8佔幾個字節?UTF-8是固定字長編碼仍是動態字長編碼的?windows

A:UTF-8編碼下一個中文所佔字節也是不肯定的。多是2個、3個、4個字節。所以可見UTF-8是變長的編碼格式的。網絡

 

擴展講解

先從字符編碼講起編碼

一、美國人首先對其英文字符進行了編碼,也就是最先的ASCII碼,用一個字節的低7位來表示英文的128個字符,高1位統一爲0spa

二、後來歐洲人發現尼瑪你這128位哪夠用,好比我高貴的法國人字母上面的還有註音符,這個怎麼區分?得,把高1位編進來吧,這樣歐洲廣泛使用一個全字節進行編碼,最多可表示256位。歐美人就是喜歡直來直去,字符少,編碼用得位數少翻譯

三、可是即便位數少,不一樣國家地區用不一樣的字符編碼,雖然0--127表示的符號是同樣的。可是128--255這一段的解釋徹底亂套了,即便2進制徹底同樣,表示的字符徹底不同。好比135在法語,希伯來語,俄語編碼中徹底是不一樣的符號。更麻煩的是,尼瑪這電腦高科技傳到中國後,中國人發現咱們有10萬多個漢字,大家歐美這256字塞牙縫都不夠。因而就發明了GB2312這些漢字編碼,典型的用2個字節來表示絕大部分的經常使用漢字,最多能夠表示65536個漢字字符,這樣就不難理解有些漢字你在新華字典裏查獲得,可是電腦上若是不處理一下你是顯示不出來的了吧設計

四、這下各用各的字符集編碼,這世界咋統一?
俄國人發封Email給中國人,兩邊字符集編碼不一樣,尼瑪顯示都是亂碼啊。爲了統一,因而就發明了Unicode,將世界上全部的符號都歸入其中,每個符號都給予一個獨一無二的編碼,如今Unicode能夠容納100多萬個符號,每一個符號的編碼都不同,這下可統一了,全部語言均可以互通,一個網頁頁面裏能夠同時顯示各國文字code

五、然而,Unicode雖然統一了全世界字符的二進制編碼,但沒有規定如何存儲啊,親。x86和amd體系結構的電腦小端序和大端序都分不清,別提計算機如何識別究竟是Unicode仍是ASCII了。
若是Unicode統一規定,每一個符號用三個或四個字節表示,那麼每一個英文字母前都必然有二到三個字節是0,文本文件的大小會所以大出二三倍,這對於存儲來講是極大的浪費。
這樣致使一個後果:出現了Unicode的多種存儲方式orm

六、互聯網的興起,網頁上要顯示各類字符,必須統一啊,親。UTF-8就是Unicode最重要的實現方式之一。另外還有UTF-1六、UTF-32等。UTF-8不是固定字長編碼的,而是一種變長的編碼方式它可使用1~4個字節表示一個符號,根據不一樣的符號而變化字節長度。這是種比較巧妙的設計,若是一個字節的第一位是0,則這個字節單獨就是一個字符;若是第一位是1,則連續有多少個1,就表示當前字符佔用多少個字節blog

七、注意Unicode的字符編碼和UTF-8的存儲編碼表示是不一樣的,例如"嚴"字的Unicode碼是4E25,UTF-8編碼是E4B8A5,這個7裏面解釋了的,UTF-8編碼不只考慮了編碼,還考慮了存儲,E4B8A5是在存儲識別編碼的基礎上塞進了4E25

八、UTF-8 使用一至四個字節爲每一個字符編碼。128 個 ASCII 字符(Unicode 範圍由 U+0000 至 U+007F)只需一個字節,帶有變音符號的拉丁文、希臘文、西裏爾字母、亞美尼亞語、希伯來文、阿拉伯文、敘利亞文及馬爾代夫語(Unicode 範圍由 U+0080 至 U+07FF)須要二個字節,其餘基本多文種平面(BMP)中的字符(CJK屬於此類-Qieqie注)使用三個字節,其餘 Unicode 輔助平面的字符使用四字節編碼。

九、最後,常規來看,中文漢字在UTF-8中到底佔幾個字節,通常是3個字節,最多見的編碼方式是1110xxxx 10xxxxxx

 

幾種編碼格式的簡單介紹

  • ASCII 碼

學過計算機的人都知道 ASCII 碼,總共有 128 個,用一個字節的低 7 位表示,0~31 是控制字符如換行回車刪除等;32~126 是打印字符,能夠經過鍵盤輸入而且可以顯示出來。

  • ISO-8859-1

128 個字符顯然是不夠用的,因而 ISO 組織在 ASCII 碼基礎上又制定了一些列標準用來擴展 ASCII 編碼,它們是 ISO-8859-1~ISO-8859-15,其中 ISO-8859-1 涵蓋了大多數西歐語言字符,全部應用的最普遍。ISO-8859-1 仍然是單字節編碼,它總共能表示 256 個字符。

  • GB2312

它的全稱是《信息交換用漢字編碼字符集 基本集》,它是雙字節編碼,總的編碼範圍是 A1-F7,其中從 A1-A9 是符號區,總共包含 682 個符號,從 B0-F7 是漢字區,包含 6763 個漢字。

  • GBK

全稱叫《漢字內碼擴展規範》,是國家技術監督局爲 windows95 所制定的新的漢字內碼規範,它的出現是爲了擴展 GB2312,加入更多的漢字,它的編碼範圍是 8140~FEFE(去掉 XX7F)總共有 23940 個碼位,它能表示 21003 個漢字,它的編碼是和 GB2312 兼容的,也就是說用 GB2312 編碼的漢字能夠用 GBK 來解碼,而且不會有亂碼。

  • GB18030

全稱是《信息交換用漢字編碼字符集》,是我國的強制標準,它多是單字節、雙字節或者四字節編碼,它的編碼與 GB2312 編碼兼容,這個雖然是國家標準,可是實際應用系統中使用的並不普遍。

  • UTF-16

說到 UTF 必需要提到 Unicode(Universal Code 統一碼),ISO 試圖想建立一個全新的超語言字典,世界上全部的語言均可以經過這本字典來相互翻譯。可想而知這個字典是多麼的複雜,關於 Unicode 的詳細規範能夠參考相應文檔。Unicode 是 Java 和 XML 的基礎,下面詳細介紹 Unicode 在計算機中的存儲形式。

UTF-16 具體定義了 Unicode 字符在計算機中存取方法。UTF-16 用兩個字節來表示 Unicode 轉化格式,這個是定長的表示方法,不論什麼字符均可以用兩個字節表示,兩個字節是 16 個 bit,因此叫 UTF-16。UTF-16 表示字符很是方便,每兩個字節表示一個字符,這個在字符串操做時就大大簡化了操做,這也是 Java 以 UTF-16 做爲內存的字符存儲格式的一個很重要的緣由。

  • UTF-8

UTF-16 統一採用兩個字節表示一個字符,雖然在表示上很是簡單方便,可是也有其缺點,有很大一部分字符用一個字節就能夠表示的如今要兩個字節表示,存儲空間放大了一倍,在如今的網絡帶寬還很是有限的今天,這樣會增大網絡傳輸的流量,並且也不必。而 UTF-8 採用了一種變長技術,每一個編碼區域有不一樣的字碼長度。不一樣類型的字符能夠是由 1~4 個字節組成。

UTF-8 有如下編碼規則:
若是一個字節,最高位(第 8 位)爲 0,表示這是一個 ASCII 字符(00 - 7F)。可見,全部 ASCII 編碼已是 UTF-8 了。
若是一個字節,以 11 開頭,連續的 1 的個數暗示這個字符的字節數,例如:110xxxxx 表明它是雙字節 UTF-8 字符的首字節。
若是一個字節,以 10 開始,表示它不是首字節,須要向前查找才能獲得當前字符的首字節

代碼示例

public class CharacterDemo {

    public static void main(String [] args) {

        String chinese = "中";
        String english = "A";
        String cha = "0x20001";
        int c = 0x20001;
        CharacterDemo.characterTest(english);
        System.out.println("=============以上是英文字符輸出信息=================");

        CharacterDemo.characterTest(chinese);
        System.out.println("=============以上是中文字符輸出信息=================");

        CharacterDemo.characterTest(cha);
        System.out.println("==========================================");

        CharacterDemo.binaryTest(c);
        System.out.println("==========================================");
    }

    private static void characterTest(String str) {
        CharacterDemo.getLengthByEncodeing(str,"GB2312");
        CharacterDemo.getLengthByEncodeing(str,"GBK");
        CharacterDemo.getLengthByEncodeing(str,"GB2312");
        CharacterDemo.getLengthByEncodeing(str,"GB18030");
        CharacterDemo.getLengthByEncodeing(str,"ISO-8859-1");
        CharacterDemo.getLengthByEncodeing(str,"UTF-8");
        CharacterDemo.getLengthByEncodeing(str,"UTF-16");
        CharacterDemo.getLengthByEncodeing(str,"UTF-16BE");
        CharacterDemo.getLengthByEncodeing(str,"UTF-16LE");
    }

    private static void binaryTest(int c) {
        char[] arr = Character.toChars(c);
        String s = new String(arr);
        System.out.println("char array length:" + arr.length);
        System.out.println("content:|  " + s + " |");
        System.out.println("String length:" + s.length());

        CharacterDemo.getLengthByEncodeing(s, "GB2312");
        CharacterDemo.getLengthByEncodeing(s, "GBK");
        CharacterDemo.getLengthByEncodeing(s, "GB2312");
        CharacterDemo.getLengthByEncodeing(s, "GB18030");
        CharacterDemo.getLengthByEncodeing(s, "ISO-8859-1");
        CharacterDemo.getLengthByEncodeing(s, "UTF-8");
        CharacterDemo.getLengthByEncodeing(s, "UTF-16");
        CharacterDemo.getLengthByEncodeing(s, "UTF-16BE");
        CharacterDemo.getLengthByEncodeing(s, "UTF-16LE");
    }

    private static void getLengthByEncodeing(String str, String encodingName) {
        try {
            System.out.format("編碼格式:%s\t\t", encodingName);
            System.out.format("字節長度:%s\n",str.getBytes(encodingName).length);
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}
編碼格式:GB2312        字節長度:1
編碼格式:GBK           字節長度:1
編碼格式:GB2312        字節長度:1
編碼格式:GB18030       字節長度:1
編碼格式:ISO-8859-1    字節長度:1
編碼格式:UTF-8         字節長度:1
編碼格式:UTF-16        字節長度:4
編碼格式:UTF-16BE      字節長度:2
編碼格式:UTF-16LE      字節長度:2
=============以上是英文字符輸出信息=================
編碼格式:GB2312        字節長度:2
編碼格式:GBK           字節長度:2
編碼格式:GB2312        字節長度:2
編碼格式:GB18030       字節長度:2
編碼格式:ISO-8859-1    字節長度:1
編碼格式:UTF-8         字節長度:3
編碼格式:UTF-16        字節長度:4
編碼格式:UTF-16BE      字節長度:2
編碼格式:UTF-16LE      字節長度:2
=============以上是中文字符輸出信息=================
編碼格式:GB2312        字節長度:7
編碼格式:GBK           字節長度:7
編碼格式:GB2312        字節長度:7
編碼格式:GB18030       字節長度:7
編碼格式:ISO-8859-1    字節長度:7
編碼格式:UTF-8         字節長度:7
編碼格式:UTF-16        字節長度:16
編碼格式:UTF-16BE      字節長度:14
編碼格式:UTF-16LE      字節長度:14
==========================================
char array length:2
content:|  𠀁 |
String length:2
編碼格式:GB2312        字節長度:1
編碼格式:GBK           字節長度:1
編碼格式:GB2312        字節長度:1
編碼格式:GB18030       字節長度:4
編碼格式:ISO-8859-1    字節長度:1
編碼格式:UTF-8         字節長度:4
編碼格式:UTF-16        字節長度:6
編碼格式:UTF-16BE      字節長度:4
編碼格式:UTF-16LE      字節長度:4
==========================================
相關文章
相關標籤/搜索