亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 操作系統 > 正文

十分鐘搞清字符集和字符編碼

2024-06-28 13:22:18
字體:
來源:轉載
供稿:網友
十分鐘搞清字符集和字符編碼

本博客已經遷移至:http://cenalulu.github.io/

本篇博文已經遷移,閱讀全文請點擊:http://cenalulu.github.io/linux/character-encoding/

本文將簡述字符集,字符編碼的概念。以及在遭遇亂碼時的一些常用診斷技巧

背景:字符集和編碼無疑是IT菜鳥甚至是各種大神的頭痛問題。當遇到紛繁復雜的字符集,各種火星文和亂碼時,問題的定位往往變得非常困難。本文就將會從原理方面對字符集和編碼做個簡單的科普介紹,同時也會介紹一些通用的亂碼故障定位的方法以方便讀者以后能夠更從容的定位相關問題。在正式介紹之前,先做個小申明:如果你希望非常精確的理解各個名詞的解釋,那么可以查閱wikipedia。本文是博主通過自己理解消化后并轉化成易懂淺顯的表述后的介紹。


什么是字符集

在介紹字符集之前,我們先了解下為什么要有字符集。我們在計算機屏幕上看到的是實體化的文字,而在計算機存儲介質中存放的實際是二進制的比特流。那么在這兩者之間的轉換規則就需要一個統一的標準,否則把我們的U盤查到老板的電腦上文檔就亂碼了,小伙伴QQ上傳過來的文件在我們本地打開又亂碼了。(PS:這里科普下亂碼的英文native說法是mojibake)。于是為了實現轉換標準,各種字符集標準就出現了。簡單的說字符集就規定了某個文字對應的二進制數字存放方式(編碼)和某串二進制數值代表了哪個文字(解碼)的轉換關系。那么為什么會有那么多字符集標準呢?這個問題實際非常容易回答。問問自己為什么我們的插頭拿到英國就不能用了呢?為什么顯示器同時有DVI,VGA,HDMI,DP這么多接口呢?很多規范和標準在最初制定時并不會意識到這將會是以后全球普適的準則,或者處于組織本身利益就想從本質上區別于現有標準。于是,就產生了那么多具有相同效果但又不相互兼容的標準了。說了那么多我們來看一個實際例子,下面就是這個字在各種編碼下的十六進制和二進制編碼結果,怎么樣有沒有一種很屌的感覺?

字符集16進制編碼
UTF-80xE5B18C
UTF-160x5C4C
GBK0x8CC5

什么是字符編碼

字符集只是一個規則集合的名字,對應到真實生活中,字符集就是對某種語言的稱呼。例如:英語,漢語,日語。而如何用英語來表達你狠屌的意思就是英語詞法語法所需要具體描述的內容了。而對于一個字符集來說要正確編碼轉碼一個字符需要三個關鍵元素:字庫表(character repertoire)、編碼字符集(coded character set)、字符編碼(character encoding form)。其中字庫表是一個相當于所有可讀或者可顯示字符的數據庫,字庫表決定了整個字符集能夠展現表示的所有字符的范圍。編碼字符集,即用一個編碼值code point來表示一個字符在字庫中的位置。字符編碼,將編碼字符集和實際存儲數值之間的轉換關系。一般來說都會直接將code point的值作為編碼后的值直接存儲。例如在ASCII中A在表中排第65位,而編碼后A的數值是0100 0001也即十進制的65的二進制轉換結果。看到這里,可能很多讀者都會有和我當初一樣的疑問:字庫表編碼字符集看來是必不可少的,那既然字庫表中的每一個字符都有一個自己的序號,直接把序號作為存儲內容就好了。為什么還要多此一舉通過字符編碼把序號轉換成另外一種存儲格式呢?其實原因也比較容易理解:統一字庫表的目的是為了能夠涵蓋世界上所有的字符,但實際使用過程中會發現真正用的上的字符相對整個字庫表來說比例非常低。例如中文地區的程序幾乎不會需要日語字符,而一些英語國家甚至簡單的ASCII字庫表就能滿足基本需求。而如果把每個字符都用字庫表中的序號來存儲的話,每個字符就需要3個字節(這里以Unicode字庫為例),這樣對于原本用僅占一個字符的ASCII編碼的英語地區國家顯然是一個額外成本(存儲體積是原來的三倍)。算的直接一些,同樣一塊硬盤,用ASCII可以存1500篇文章,而用3字節Unicode序號存儲只能存500篇。于是就出現了UTF-8這樣的變長編碼。在UTF-8編碼中原本只需要一個字節的ASCII字符,仍然只占一個字節。而像中文及日語這樣的復雜字符就需要2個到3個字節來存儲。


UTF-8和Unicode的關系

看完上面兩個概念解釋,那么解釋UTF-8和Unicode的關系就比較簡單了。Unicode就是上文中提到的編碼字符集,而UTF-8就是字符編碼,即Unicode規則字庫的一種實現形式。隨著互聯網的發展,對同一字庫集的要求越來越迫切,Unicode標準也就自然而然的出現。它幾乎涵蓋了各個國家語言可能出現的符號和文字,并將為他們編號。詳見:Unicode on Wikipedia。Unicode的編號從0000開始一直到10FFFF共分為16個Plane,每個Plane中有65536個字符。而UTF-8則只實現了第一個Plane,可見UTF-8雖然是一個當今接受度最廣的字符集編碼,但是它并沒有涵蓋整個Unicode的字庫,這也造成了它在某些場景下對于特殊字符的處理困難(下文會有提到)。


UTF-8編碼簡介

為了更好的理解后面的實際應用,我們這里簡單的介紹下UTF-8的編碼實現方法。即UTF-8的物理存儲和Unicode序號的轉換關系。UTF-8編碼為變長編碼。最小編碼單位(code unit)為一個字節。一個字節的前1-3個bit為描述性部分,后面為實際序號部分。

  • 如果一個字節的第一位為0,那么代表當前字符為單字節字符,占用一個字節的空間。0之后的所有部分(7個bit)代表在Unicode中的序號。
  • 如果一個字節以110開頭,那么代表當前字符為雙字節字符,占用2個字節的空間。110之后的所有部分(7個bit)代表在Unicode中的序號。且第二個字節以10開頭
  • 如果一個字節以1110開頭,那么代表當前字符為三字節字符,占用3個字節的空間。110之后的所有部分(7個bit)代表在Unicode中的序號。且第二、第三個字節以10開頭
  • 如果一個字節以10開頭,那么代表當前字節為多字節字符的第二個字節。10之后的所有部分(6個bit)代表在Unicode中的序號。

具體每個字節的特征可見下表,其中x代表序號部分,把各個字節中的所有x部分拼接在一起就組成了在Unicode字庫中的序號

Byte 1Byte 2
0xxx xxxx
110x xxxx10xx xxxx
1110 xxxx10xx xxxx

我們分別看三個從一個字節到三個字節的UTF-8編碼例子:

實際字符|在Unicode字庫序號的十六進制|在Unicode字庫序號的二進制|UTF-8編碼后的二進制|UTF-8編碼后的十六進制$|0024|010 0100 |0010 0100|24?|00A2|000 1010 0010|1100 0010 1010 0010|C2 A2€|20AC|0010 0000 1010 1100|1110 0010 1000 0010 1010 1100|E2 82 AC

細心的讀者不難從以上的簡單介紹中得出以下規律:

  • 3個字節的UTF-8十六進制編碼一定是以E開頭的
  • 2個字節的UTF-8十六進制編碼一定是以CD開頭的
  • 1個字節的UTF-8十六進制編碼一定是以比8小的數字開頭的

為什么會出現亂碼

簡單的說亂碼的出現是因為:編碼和解碼時用了不同或者不兼容的字符集。對應到真實生活中,就好比是一個英國人為了表示祝福在紙上寫了bless(編碼過程)。而一個法國人拿到了這張紙,由于在法語中bless表示受傷的意思,所以認為他想表達的是受傷(解碼過程)。這個就是一個現實生活中的亂碼情況。在計算機科學中一樣,一個用UTF-8編碼后的字符,用GBK去解碼。由于兩個字符集的字庫表不一樣,同一個漢字在兩個字符表的位置也不同,最終就會出現亂碼。我們來看一個例子:假設我們用UTF-8編碼存儲很屌兩個字,會有如下轉換:

字符UTF-8編碼后的十六進制
E5BE88
E5B18C

于是我們得到了E5BE88E5B18C這么一串數值。而顯示時我們用GBK解碼進行展示,通過查表我們獲得以下信息:

兩個字節的十六進制數值GBK解碼后對應的字符
E5BE
88E5
B18C

解碼后我們就得到了寰堝睂這么一個錯誤的結果,更要命的是連字符個數都變了。


如何識別亂碼的本來想要表達的文字

要從亂碼字符中反解出原來的正確文字需要對各個字符集編碼規則有較為深刻的掌握。但是原理很簡單,這里用最常見的UTF-8被錯誤用GBK展示時的亂碼為例,來說明具體反解和識別過程。

第1步 編碼

假設我們在頁面上看到寰堝睂這樣的亂碼,而又得知我們的瀏覽器當前使用GBK編碼。那么第一步我們就能先通過GBK把亂碼編碼成二進制表達式。當然查表編碼效率很低,我們也可以用以下SQL語句直接通過MySQL客戶端來做編碼工作:{% highlight mysql %}{% raw %}mysql [localhost] {msandbox} > select hex(convert('寰堝睂' using gbk));+-------------------------------------+| hex(convert('寰堝睂' using gbk)) |+-------------------------------------+| E5BE88E5B18C |+-------------------------------------+1 row in set (0.01 sec){% endraw %}{% endhighlight %}

第2步 識別

現在我們得到了解碼后的二進制字符串E5BE88E5B18C。然后我們將它按字節拆開。

Byte 1Byte 2Byte 3Byte 4Byte 5Byte 6
E5BE88E5B18C

然后套用之前UTF-8編碼介紹章節中總結出的規律,就不難發現這6個字節的數據符合UTF-8編碼規則。如果整個數據流都符合這個規則的話,我們就能大膽假設亂碼之前的編碼字符集是UTF-8

第3步 解碼

然后我們就能拿著E5BE88E5B18C用UTF-8解碼,查看亂碼前的文字了。當然我們可以不查表直接通過SQL獲得結果:{% highlight mysql %}{% raw %}mysql [localhost] {msandbox} ((none)) > select convert(0xE5BE88E5B18C using utf8);+------------------------------------+| convert(0xE5BE88E5B18C using utf8) |+------------------------------------+| 很屌 |+------------------------------------+1 row in set (0.00 sec){% endraw %}{% endhighlight %}

常見問題處理之Emoji

所謂Emoji就是一種在Unicode位于/u1F601-/u1F64F區段的字符。這個顯然超過了目前常用的UTF-8字符集的編碼范圍/u0000-/uFFFF。Emoji表情隨著IOS的普及和微信的支持越來越常見。下面就是幾個常見的Emoji:emoji1emoji2emoji3那么Emoji字符表情會對我們平時的開發運維帶來什么影響呢?最常見的問題就在于將他存入MySQL數據庫的時候。一般來說MySQL數據庫的默認字符集都會配置成UTF-8(三字節),而utf8mb4在5.5以后才被支持,也很少會有DBA主動將系統默認字符集改成utf8mb4。那么問題就來了,當我們把一個需要4字節UTF-8編碼才能表示的字符存入數據庫的時候就會報錯:ERROR 1366: Incorrect string value: '/xF0/x9D/x8C/x86' for column 。 如果認真閱讀了上面的解釋,那么這個報錯也就不難看懂了。我們試圖將一串Bytes插入到一列中,而這串Bytes的第一個字節是/xF0意味著這是一個四字節的UTF-8編碼。但是當MySQL表和列字符集配置為UTF-8的時候是無法存儲這樣的字符的,所以報了錯。那么遇到這種情況我們如何解決呢?有兩種方式:升級MySQL到5.6或更高版本,并且將表字符集切換至utf8mb4。第二種方法就是在把內容存入到數據庫之前做一次過濾,將Emoji字符替換成一段特殊的文字編碼,然后再存入數據庫中。之后從數據庫獲取或者前端展示時再將這段特殊文字編碼轉換成Emoji顯示。第二種方法我們假設用-*-1F601-*-來替代4字節的Emoji,那么具體實現python代碼如下

reference

如何配置Python默認字符集字符編碼筆記:ASCII,Unicode和UTF-8Unicode中文編碼表Emoji Unicode Table


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲国产精品99| 欧美一级黑人aaaaaaa做受| 欧美性高跟鞋xxxxhd| 日本中文字幕不卡免费| 欧美成人免费全部| 国产午夜精品视频| 国产精品欧美久久久| 久久天天躁狠狠躁夜夜av| 国产精品99久久久久久白浆小说| 久久久女女女女999久久| 国产精品亚洲综合天堂夜夜| 国产综合在线视频| 伊人久久久久久久久久久久久| 久久成人这里只有精品| 九九久久久久久久久激情| 78m国产成人精品视频| 91牛牛免费视频| 欧美亚洲免费电影| 久久精品视频免费播放| 草民午夜欧美限制a级福利片| 国产日韩在线看片| 97涩涩爰在线观看亚洲| 国产一区二区三区精品久久久| 97在线观看免费| 欧美精品久久久久a| 欧美性感美女h网站在线观看免费| 久久午夜a级毛片| 国产欧美日韩免费看aⅴ视频| 日韩av在线电影网| 精品亚洲精品福利线在观看| 色香阁99久久精品久久久| 国产日产亚洲精品| 91免费福利视频| 国产99久久精品一区二区 夜夜躁日日躁| 亚洲天堂2020| 欧美极品少妇xxxxⅹ裸体艺术| 亚洲女人被黑人巨大进入| 在线成人免费网站| 91精品久久久久久久久青青| 26uuu久久噜噜噜噜| 欧美成人激情视频| 精品国产福利在线| 欧美成人精品在线| 欧洲午夜精品久久久| 成人国产在线激情| 亚洲免费电影一区| 国产精品午夜一区二区欲梦| 国产精品成人国产乱一区| 91精品国产色综合久久不卡98| 国产成人啪精品视频免费网| 成人激情综合网| 日本最新高清不卡中文字幕| 亚洲激情视频在线| 久99久在线视频| 国产精品久久久久秋霞鲁丝| 欧美激情在线观看| 亚洲精品国精品久久99热| 日韩中文字幕在线播放| 亚洲乱码国产乱码精品精| 97激碰免费视频| 欧美日韩视频在线| 91精品视频观看| 乱亲女秽乱长久久久| 91久久久久久久久久久久久| 久久手机精品视频| 韩日欧美一区二区| 中文字幕一区二区三区电影| 琪琪第一精品导航| 欧美精品videossex性护士| 96精品视频在线| 久久久久久国产免费| 伊人伊成久久人综合网站| 日韩毛片在线看| 亚洲国产三级网| 美日韩精品视频免费看| 日韩经典中文字幕| 好吊成人免视频| 亚洲aⅴ日韩av电影在线观看| 成人国产精品免费视频| 亚洲欧美日韩在线一区| 欧美电影免费看| 精品国产老师黑色丝袜高跟鞋| 奇门遁甲1982国语版免费观看高清| 国产成人一区二区三区电影| 亚洲视频在线播放| 欧美成人sm免费视频| 97在线日本国产| 91免费人成网站在线观看18| 久久久视频在线| 亚洲欧美日韩第一区| 免费av一区二区| 国产精品wwwwww| 欧美高清自拍一区| 亚洲春色另类小说| 中文字幕亚洲在线| 久久精品视频99| 国产成人av网| 日韩精品在线观| 久久久久久久久久久av| 日韩av电影国产| 久久成人精品一区二区三区| 午夜精品福利视频| 欧美在线亚洲一区| 久久久亚洲天堂| 亚洲第一av网站| 国产精品亚洲第一区| 国产亚洲视频中文字幕视频| 精品久久久久久中文字幕一区奶水| 国产a级全部精品| 中文日韩在线视频| 亚洲伊人成综合成人网| 色午夜这里只有精品| 成人在线视频网站| 国产精品一区二区三区在线播放| 奇门遁甲1982国语版免费观看高清| 日本一区二三区好的精华液| 欧美激情一级精品国产| 亚洲国产中文字幕久久网| 亚洲精品永久免费精品| 国产精品美女久久久久av超清| 精品久久久999| 国产精品国产自产拍高清av水多| 精品国产网站地址| 欧美巨乳在线观看| 爽爽爽爽爽爽爽成人免费观看| 91精品久久久久久久久中文字幕| 亚洲精品美女久久| 国产精品男人爽免费视频1| 日韩av日韩在线观看| 国产欧美日韩免费看aⅴ视频| 不卡在线观看电视剧完整版| 91嫩草在线视频| 久久伊人91精品综合网站| 亚洲视频自拍偷拍| 欧美大片免费观看| 欧美午夜女人视频在线| 国产91精品不卡视频| 国产97在线视频| 国产精品福利久久久| 久久久噜噜噜久久| 欧美尺度大的性做爰视频| 欧美大片在线免费观看| 91精品视频免费| 成人在线视频网| 欧美老女人在线视频| 黄色成人在线播放| 精品夜色国产国偷在线| 久久的精品视频| 97超级碰在线看视频免费在线看| 狠狠久久亚洲欧美专区| 亚洲精品美女网站| 国产精品露脸自拍| 高清亚洲成在人网站天堂| 欧美高清视频一区二区| 精品国产乱码久久久久久婷婷| 久久777国产线看观看精品| 亚洲国产精品va在线| 最新中文字幕亚洲| 色综合久久精品亚洲国产| 成人春色激情网| 亚洲黄色有码视频| 欧美成年人网站| 亚洲精品视频播放| 91免费国产网站|