日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

我都服了,为啥上游接口返回的汉字总是乱码?

發布時間:2025/3/16 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 我都服了,为啥上游接口返回的汉字总是乱码? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

想必大家編寫代碼時肯定和我一樣,也遇到過漢字亂碼的問題。特別是,有時候和上下游對接接口,不能統一編碼格式的話,一堆亂碼問題,讓人頭皮發麻。

那么為什么會有這么多的亂碼問題?

什么是字符編碼?什么是字符集?他們之間有什么區別和聯系?

什么是 Unicode ?Unicode 和我們常說的 UTF-8 又有什么關系?

?

字符編碼和解碼

要想搞清楚上面的問題,首先我們要知道,在計算機中,不管是一段文字、一張圖片還是一段視頻,最終都是以二進制的方式來存儲。也就是最終都會轉化為 0001 1011 0010 0110 ?這樣的格式。

換句話說,計算機只認識 0 和 1 這樣的數字,并不能直接存儲字符。所以我們需要告訴它什么樣的字符對應的是什么數字。

例如,我們的業務中有記錄客戶端的客戶行為日志,然后導出文件來分析,字段間會以 ESC 來分隔。

我在編寫代碼的時候,就需要定義一下這個ESC 字符應該對應什么數字,這樣計算機才能識別并存儲。

比如我把它定為 0001 1011,這樣計算機就把 ESC 這個字符存了下來。等我下次需要查看的時候,根據對應關系把它解出來就可以了。

上邊的兩個過程就對應字符的編碼和解碼過程。

字符編碼就是把字符按一定的規則,轉換成數字。字符解碼是編碼的逆過程,即把數字按規則轉換成字符。

這樣看來,貌似沒有什么問題。

但是,這是我自己定義的編碼規則,我同桌阿霄就不樂意了。他非要認為 ESC 應該定義為 1101 1000,好家伙正好和我定義的二進制數字順序相反。

那結果肯定不用說了,我把 0001 1011 這串數字給他之后,按照他的編碼規則來解,肯定是 &$#!這樣的東西。

所以,亂碼問題說到底,就是編碼和解碼的規則對應不上導致的。

?

ASCII 碼

為了避免我和阿霄因為編碼問題打起來,美國國家標準學會(AMERICAN NATIONAL STANDARDS INSTITUTE) ANSI 組織發話了。

停、停、停。不就是個編碼問題嗎,這種小事犯不著動手,我定義一個統一的規則,大家都按照我的規則來編碼和解碼不就好了嘛。

于是,ASCII 碼出現了,它定義了一個常用字符集,用來表示字符和數字的對應關系,如下表。

ASCII 碼全稱:美國信息交換標準代碼 (American Standard Code for Information Interchange)

圖片來自百度圖片

我一查表,ESC 字符不就對應 27 嗎,對應的二進制就是 0001 1011 。我去,沒想到我定義的規則竟和 ANSI 不謀而合。

同桌阿霄把掄在空中的拳頭收了起來,默默地回去敲代碼了。

?

ASCII 碼擴展碼

在使用英語的國家,ASCII 碼就足夠用了。但是,在其他歐洲發達國家比如法國,使用的語言是法語,有類似于這樣的 á 符號,ASCII 碼就不能表示了。那怎么辦呢?

我們看上表就會發現,ASCII 碼表的表示范圍是十進制 0~127,也就是二進制 0000 0000 到 0111 1111 。其實只是用了后邊的 7 位,第一位都是 0 。

而計算機二進制中一個字節是 8 個位,現在只用了 7 位。不行啊太浪費了,要充分利用第一個高位,擴展一下,這樣多了一位,能表示的字符范圍就多了一倍。(2的8次方=256)

這樣一些歐洲其他國家,也能在計算機中表示自己的文字了。

后來,隨著計算機的普及,中國的用戶也多了起來。卻發現,一個字節只能表示 256 個字符,遠遠不能滿足我們的要求。

于是,就出現了 GB2312 編碼,它使用了兩個字節來表示一個漢字。但是,并沒有把所有的位都用完,前面一個字節范圍 0xA1 ~ 0xF7 (即 10110001 ~ 11110111),后面一個字節范圍 0xA1 ~ 0xFE (即 10110001 ~ 11111110) 。這樣就能表示簡體漢字 6763 個。

GB2312 是國家標準總局發布的《信息交換用漢字編碼字符集》,也可以說是簡體中文的字符集。

但是,臺灣和香港等使用繁體字的地區怎么辦。于是,就有了大五碼 Big5 編碼來存儲繁體。高字節(第一個字節)表示范圍 0x81~0xFE,低字節(第二個字節)表示范圍 ?0x40 ~ 0x7E,以及0xA1 ~ 0xFE 。

需要注意的是,GB2312 是簡體中文,Big5 是繁體中文。如果用其中一種編碼文字去讀另外一種編碼文字就會亂碼。所以,就出來了 GBK 編碼,把簡體中文和繁體中文,以及一些 GB2312 不支持的人名(如歷代總理有的名字用 GB2312 打不出來),還有一些我們不認識的古漢語都包含進去,共 2 萬多個字符。

再然后,我們發現少數民族像藏文,蒙古文這些少數民族的語言,GBK 也支持不了,就再進行擴展,出現了 GB18030 。又多了幾千個少數民族的文字。

所以,我們使用的 GB 國標系列文字都是在 ASCII 碼之上擴展的,它們是依次向下兼容的。表示文字范圍從小到大為 GB2312 = Big5 < GBK < GB18030 。

?

Unicode 字符集

我們在打開一個文檔之前,就必須要知道它的編碼格式,否則用錯誤的方式解碼就會出現亂碼情況。

設想,如果一個文本中,有多種類型文字,包括中文,韓語,德語,日語,應該用哪種編碼方式?貌似怎么處理都會有亂碼問題,那怎么辦呢?

ISO(國際標準化組織)說:這好辦啊,我把地球上,只要是人們使用的,所有語言和符號都囊括其中,為每個字符都指定一個唯一的字符碼,這樣就沒有亂碼問題了。于是 Unicode 出現了,又叫統一碼,萬國碼。

如上圖表,漢字“一”對應的 unicode 碼是 \u4e00。我們通常在字符碼前加個 \u代表這是 unicode 碼。4e00 是十六進制表示。

也有很多在線轉碼工具供我們使用,如:http://tool.chinaz.com/tools/unicode.aspx

?

Unicode 編碼方案

首先強調一下以下幾個概念的區別:

  • 字符:就是我們看到的一個字母或一個漢字、一個標點符號都叫字符。如上邊的漢字“一”就是一個字符。

  • 字符碼:在指定的字符集中,一個字符對應唯一一個數字,這個數字就叫字符碼。如上邊的字符“一”,在 Unicode 字符集中,對應的字符碼為 \u4e00。

  • 字符集:規定了字符和字符碼之間的對應關系。

  • 字符編碼:規定了一個字符碼在計算機中如何存儲。

  • 需要注意的是,Unicode 只是一個字符集,它規定了每個字符對應的唯一字符碼,卻沒有規定這個字符碼在計算機中怎樣存儲(也就是它的字符編碼格式)。

    例如,上邊的漢字“一”,它的 Unicode 字符碼為 \u4e00,轉換成二進制就是 100 1110 0000 0000 。可以看到,它有 15 位二進制數,至少需要兩個字節來存儲。

    這只是簡單的漢字,如果其他復雜的字符有可能會需要 三、四 個字節或者更多字節來存儲。

    那么到底應該用幾個字節來存儲呢?

    于是 UTF-32 編碼 制定了標準,一個字符就用四個字節來表示。這樣編碼和解碼都方便,固定取 32 位二進制就行了。

    但是這樣又引來一個問題。比如 A 字符其實只需要一個字節就可以存儲了。如果必須要用四個字節來存儲,那么前邊三個字節都要補 0 ,這樣勢必會造成空間的浪費。

    于是 UTF-16 編碼(一個字符用兩個字節或者四個字節)和我們熟悉的 UTF-8 編碼格式就出現了。

    這里我們重點介紹 UTF-8 。它使用一種變長的編碼方式,可以使用 1~4 個字節來表示一個字符。根據不同的字符變換長度。

    變長聽起來很美好,但是它的不固定性,就讓計算機懵逼了。比如,計算機怎么知道這四個字節代表的是一個字符,還是四個字符,亦或是兩個字符呢?

    于是,UTF-8 規定了以下編碼規則,來避免以上問題。

    • 對于單字節的符號,第一位設為0,后邊 7 位對應這個字符的ASCII碼值。因此,像“A"這樣的英文字母,UTF-8 編碼和 ASCII 編碼是相同的。

    • 對于大于一個字節的符號,假設為 n 字節,那么第一個字節的前 n 位都設為 1,這樣有幾個 1 就說明有幾個字節。然后,第 n+1 位設為0 。后邊的字節,前兩位都設為10 ,剩余的其他二進制位都用這個字符的 Unicode 碼填充(從后向前填充,不夠補0)。

    剛開始看上表,可能比較懵逼。其實,Unicode 符號表示的范圍最大為四個字節,因此二進制為 4*8=32 位。我們知道,二進制轉換十六進制時,以四位為一個單位轉換,因此,對應的十六進制為 32/4=8 位。

    上表中的 Unicode 符號范圍是以 16 進制表示,可以看到就是 8 位的。

    我們還是以漢字 “一” 為例,16進制表示為 4e00,補全所有位,其實就是 0000 4E00 (不區分大小寫)。因此,查上表發現,它處在三個字節的 Unicode 范圍內(0000 0800 < 0000 4e00 < 0000 FFFF)。

    所以,它用 UTF-8 來編碼,就是三個字節的,即格式是這樣的 1110xxxx 10xxxxxx 10xxxxxx 。

    把 4e00 轉換為二進制為 100 1110 0000 0000,二進制位從后向前依次填充到上述格式中的x位置(也是從后向前填充)。

    于是,就得出漢字 “一” 的 UTF-8 編碼后的二進制表示為:1110 0100 1011 1000 1000 0000 。

    其實,可以發現,漢字的二進制為 15 位,前邊補零一位即為 16 位 0100 1110 0000 0000。而三個字節的 UTF-8 編碼格式中的 x 個數也為 3*8 - (4+2+2) = 16 位,正好一一對應。

    那么,我們這一通推算,是否正確呢。可以在程序中打印這個字符的二進制格式,以及UTF-8編碼后的二進制。程序如下,

    public?class?Test?{public?static?void?main(String[]?args)?throws?UnsupportedEncodingException?{System.out.println("字符'一'的二進制為:"?+?Integer.toBinaryString('一'));System.out.println("========");String?str?=?"一";System.out.println("轉換為UTF-8編碼格式的二進制為:"+?toBinary(str,"utf-8"));}public?static?String?toBinary(String?str,?String?encode)?throws?UnsupportedEncodingException?{StringBuilder?sb?=?new?StringBuilder();byte[]?bytes?=?str.getBytes(encode);for?(int?i?=?0;?i?<?bytes.length;?i++)?{byte?b?=?bytes[i];sb.append(Integer.toBinaryString(b?&?0xFF));}return?sb.toString();}}

    打印結果為:

    字符'一'的二進制為:100111000000000 ======== 轉換為UTF-8編碼格式的二進制為:111001001011100010000000

    PS:通常的,我們發現常用的漢字以 16 進制表示都在 0000 0800 ~ 0000 FFFF 范圍內。因此,漢字在 UTF-8 編碼下通常占用三個字節。

    細心的同學可能發現了,我上邊轉換的漢字可以用 char 類型來存儲,這是為什么呢?

    這是因為,在 Java 中,默認使用的字符集就是 Unicode,可以容納 100 多萬個字符,其中就包括漢字。

    我們使用的絕對大多數漢字,都在0000 0800 ~ 0000 FFFF 這個范圍內,可以看出來前邊的四位十六進制都用不到(都是0000),因此,只需要后邊的四位十六進制位,轉換為二進制就是 4*4=16 位,只占用了兩個字節(16/8=2)。而 char 在 Java 中占用兩個字節,完全可以用來存儲漢字。

    ?

    總結

    最后,來解答下文章開頭的問題。

    亂碼的問題,究其根本原因,其實是編碼和解碼時的規則不一樣導致的。

    字符編碼和字符集是兩個不同的概念。一句話表示:字符集定義了字符到數字的映射關系,字符編碼定義了這個數字如何在計算機中表達(存儲)。

    對于 ASCII 和 GB 系列,他們既是字符集也是字符編碼。GB 兼容 ASCII 碼。

    而對于 Unicode 來說,字符集是 Unicode,而字符編碼可以是 UTF-8,UTF-16 和 UTF-32 。所以,我們平時常用的 UTF-8 編碼其實只是 Unicode 的一種編碼實現方式而已。

    有道無術,術可成;有術無道,止于術

    歡迎大家關注Java之道公眾號

    好文章,我在看??

    總結

    以上是生活随笔為你收集整理的我都服了,为啥上游接口返回的汉字总是乱码?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 干干天天| 91丝袜呻吟高潮美腿白嫩在线观看 | 亚洲综合免费观看高清完整版 | av大片网站 | 一区二区三区免费看视频 | 久久久久久欧美精品se一二三四 | 小婕子伦流澡到高潮h | 国产美女毛片 | 日韩黄色av | 国产精品vip | 夜色一区二区三区 | 91九色偷拍 | 亚洲视频网站在线观看 | 中文字幕人妻色偷偷久久 | 99爱精品视频 | 久国产| 草逼视频网 | 欧美在线视频a | 西西4444www大胆无码 | 黄色片www| 俄罗斯黄色大片 | 久久综合影视 | 艳母免费在线观看 | 国产成人无码av | 亚洲专区一区二区三区 | 免费黄色在线网站 | 天堂精品一区二区三区 | 91日韩在线视频 | 毛片毛片毛片毛片毛片毛片毛片毛片毛片 | 人妻va精品va欧美va | 女性喷水视频 | 名校风暴在线观看免费高清完整 | 国产精品一区二区无码对白 | 日韩性av | 亚洲最大视频网 | 手机免费看av片 | jzzijzzij亚洲成熟少妇在线播放 狠狠躁日日躁夜夜躁2022麻豆 | 福利第一页 | 久久国产中文 | 欧美天天爽 | www.av.cn| 超碰99在线观看 | 国产理论影院 | 97人妻精品一区二区三区动漫 | 国产精品theporn88 | 久久久久久久久一区 | 亚洲AV无码成人精品区东京热 | 性欧美久久久 | 国产网站视频 | 第一章婶婶的性事 | 亚洲精品国产精品乱码桃花 | 女优在线观看 | 欧美日韩成人一区 | 亚洲国产日韩欧美一区二区三区 | 五十路六十路七十路熟婆 | 三级黄在线观看 | 欧美大色一区 | 欧美在线观看a | 亚洲第八页| 日韩一区不卡视频 | 红桃av| 亚洲青色在线 | 里番精品3d一二三区 | 国产美女无遮挡网站 | 少女国产免费观看 | 精品人妻伦九区久久aaa片 | 亚洲成人资源 | 欧美日韩免费网站 | 欧美日韩一区二区三区在线播放 | 国产精品国产三级国产专区51 | 美丽的姑娘观看在线播放 | 国产成人无码一二三区视频 | 爱爱的免费视频 | 俺去操 | 黄色短视频在线播放 | 国产一区中文字幕 | 欧美女人交配视频 | 五月婷婷av| 99在线精品视频免费观看20 | 国内自拍一区 | 伊人国产一区 | 久久精品一二 | 日韩av中文在线 | 一区二区三区丝袜 | 欧美自拍偷拍一区 | 阿v天堂2017| 美女黄18以下禁止观看 | 亚洲一区二区三区黄色 | 国产一区二区在线视频 | 国产成人一区在线观看 | 91精品免费看 | 91快射 | 欧美成年人视频在线观看 | 天天透天天操 | 激情图片在线观看 | 国产精品成人无码专区 | 日本一区视频在线 | 麻豆视频在线观看免费网站 | 天堂中文在线资 |