1. 程式人生 > >那些年我踩過的emoji亂碼坑

那些年我踩過的emoji亂碼坑

前言

這是一個由亂碼引發的故事。抱歉我暫時找不到更加慘烈的圖,請相信我,還有更目不忍視的畫面。請看下圖那些框框,那都是些什麼鬼!這是要害死強迫症嗎?如果同時看到幾十個框,簡直讓人崩潰。

那些年我踩過的emoji亂碼坑

問題來了,這究竟是些什麼鬼?

計算機編碼

既然是亂碼,當然要看編碼,那什麼是編碼呢?

我們都知道,計算機本質上不就是01組成的一坨東西在運作著麼?01這叫二進位制,也就是最基本最底層的編碼。 那麼大家平常看到的網頁也好,APP也好,上面的這些文字元號是怎麼表現出來的?當然是根據標記打印出來的,但計算機只能是二進位制的儲存,並不能真正存ABCD呀,那就要把字母對映為相應的二進位制。

上個世紀60年代,美國製定了一套字元編碼,對英語字元與二進位制位之間的關係,做了統一規定。這被稱為ASCII碼,一直沿用至今。

ASCII碼一共規定了128個字元的編碼,比如大寫的字母A是65(二進位制01000001)。這128個符號(包括32個不能打印出來的控制符號),只佔用了一個位元組的後面7位,最前面的1位統一規定為0。但你美國英文字母少啊,我中文怎麼辦呢?全世界其他國家的字母其他語言怎麼辦呢,那就多加一些位元組來表示咯。

如果有一種編碼,將世界上所有的符號都納入其中。每一個符號都給予一個獨一無二的編碼,那麼亂碼問題就會消失了,這就是Unicode。Unicode規定了每個符號都有自己的二進位制碼。標準雖是標準,但各平臺實現標準的進度不一啊,有的各自為政,這就有問題了,就像各大瀏覽器產商,沒給我們前端少帶來麻煩啊。簡單點說,雖然你蘋果實現了這個標準可以顯示這個符號,但我Android沒有,也不知道這個符號表達成啥,所以暫時給個框吧。

因此導致亂碼的真正原因:就是各平臺間對Unicode標準實現不一致(包括實現的時間先後不同,以及Unicode所代表含義不同)。

編碼分析

那框框的Unicode編碼到底是什麼呢?

charCodeAt() (這個方法有侷限性,後面說)方法可返回指定位置的字元的 Unicode 編碼。這個返回值是 0 – 65535 之間的整數。

" 追求簡單的小生活".charCodeAt(0) 
// 57614 

57614是個十進位制數,對應16進製為E10E,Unicode也可以表示為U+E10E。通過這個網站查詢得知結果如下:

那些年我踩過的emoji亂碼坑

一頭霧水,PRIVATE USE CODEPOINT這是個什麼意思呢?幸好下面有wiki的解釋:

In Unicode, the Private Use Areas (PUA) are three ranges of code points (U+E000–U+F8FF in the BMP, and in planes 15 and 16) that, by definition, will not be assigned characters by the Unicode Consortium. The code points in these areas can not be considered as standardized characters in Unicode itself. They are intentionally left undefined so that third parties may define their own characters without conflicting with Unicode Consortium assignments. Under the Unicode Stability Policy, the Private Use Areas will remain allocated for that purpose in all future Unicode versions.

咳咳,由於英文水平問題,但我還是勉強翻譯下。大意就是:位於BMP的U+E000–U+F8FF編碼,和第15以及16平面的區域的編碼,Unicode協會表示不會對該區域的編碼指定符號,且這些區域編碼不是標準符號,故意留下未定義的區域是讓第三方自己去玩。

那什麼又是BMP,第一個平面稱為基本多語言平面(Basic Multilingual Plane, BMP),或稱第零平面(Plane 0)。其他平面稱為輔助平面(Supplementary Planes)。最前面的65536個字元位,都在BMP中。 好了,回到前面看,U+E10E這個Unicode剛好落到了(U+E000–U+F8FF)區間內。所以這個字元是因為第三方自定義的。 網上找到了一份表,http://www.easyapns.com/iphone-emoji-ale… 。U+E10E對應符號如下:

那些年我踩過的emoji亂碼坑

那框真的是這個皇冠emoji嗎?因為是使用者暱稱,查一下就知道了
那些年我踩過的emoji亂碼坑
事實證明,確實沒錯。那麼既然是emoji表情,為什麼iphone(9.3.1)都不能正常解析?這編碼又是怎麼被使用者輸入進去的?

emoji表情

說到emoji,那我們先來扒一扒emoji的歷史故事。 emoji表情源於日本,叫做繪(e=圖)文字(moji=字元)。

Emoji were initially used by Japanese mobile operators, NTT DoCoMo, au, and SoftBank Mobile (formerly Vodafone). 日本幾家公司各自定義了一套標準,用兩個位元組表示符號,Shift-JIS(日本電腦系統的一種編碼)編碼是從F89F到F9FC。當然這已經是上世紀的事情了,其中被廣泛採用的是SoftBank標準,也稱之為SB (SoftBank,這裡不是ShaBi的縮寫,咳咳)emoji表情。

發展到今天,Unicode協會把emoji表情納入標準中,但編碼範圍重新劃分了。前面說了,Private Use Areas 是留給第三方用的,不能瞎佔用。 在這個網站查到E10E如下資訊:
那些年我踩過的emoji亂碼坑
可以初步懷疑是SoftBank的emoji表情。 恰好手中有臺舊的華為手機,有一個系統自帶的華為輸入法,輸入法裡面有一些跟蘋果emoji一樣的表情,只不過數量沒這麼多。下面四個是華為輸入法鍵盤上的表情:

那些年我踩過的emoji亂碼坑

這四個表情在Unicode中的標準編碼是:

那些年我踩過的emoji亂碼坑

注意,如果使用charCodeAt方法來獲取Unicode編碼的時候要注意了,前面我們提到了該方法有缺陷。簡單的原因就是JavaScript使用的編碼與utf-8不一樣導致,這裡不展開講,有興趣可以看這篇文章。ES6提供了新的介面來獲取碼點,codePointAt

那些年我踩過的emoji亂碼坑

輸入的結果展示如下:

  • iphone6sp 顯示框框

那些年我踩過的emoji亂碼坑

  • huawei 顯示空白

    那些年我踩過的emoji亂碼坑

雖然在兩臺機器的表現形式不一樣,但都是無法正確顯示,那我們看下這到底是什麼編碼。

那些年我踩過的emoji亂碼坑
上面四個編碼落入的區域也是在(U+E000–U+F8FF)內,然後根據上面的網站查詢,可以確認是來自SoftBank標準的emoji表情了。 所以只要替換這些編碼就好了。

解決方案

也就是說SoftBank emoji表情現在的系統基本不支援,因為已經過時了。 但為什麼使用者還能夠輸入這些SoftBank emoji呢?原因就在於有些手機輸入法(相對古老了)廠商對emoji的實現還是參照SoftBank的標準。 因此把SoftBank emoji編碼轉換為Unicode標準的就是解決之道。在

github上找到了SoftBank與標準emoji Unicode的對應關係。 有兩種解決方案:

1、轉換為html實體編碼 \uE10E -> \u1F451 ->皇冠表情
優點:

  • 高清,依賴系統編碼;

  • 不需要載入css和emoji圖片,省流量。 缺點:

  • 所有平臺表情不統一,各系統自定義的圖示,風格不同,但表達意思基本一樣那些年我踩過的emoji亂碼坑

  • 部分平臺不支援emoji

    • ios:
      那些年我踩過的emoji亂碼坑
    • android:那些年我踩過的emoji亂碼坑

2、轉換為html標籤 code 對應emoji圖示的classID,用雪碧圖。

<i class="emoji emoji'+code+'" text=""></i> 優點: 

  • 所有平臺表情統一(如果統一算優點的話,有爭議,畢竟Android使用者看習慣了Android表情)。 缺點:

  • 需要載入額外的css和emoji圖示;如果要高清(暫時無法找到,圖片會模糊),則圖示會很大。 綜上,結合方案一二,在Android版本小於4.4的時候採用方案二,其他採用方案一。

結果

那些年我踩過的emoji亂碼坑

(左邊為處理前,右邊為處理後) 不同系統的處理結果

那些年我踩過的emoji亂碼坑

那些年我踩過的emoji亂碼坑

總結

問題來了,如果遇到了其他編碼標準(google, DoCoMo,KDDI 等等)的表情該怎麼辦?如果沒有Unicode的與符號的對映關係真是白搭,你絲毫沒有辦法。就像你不學習英文單詞,你還想看懂英文文章? emoji表情不斷在豐富,這也給前端(各種終端)工作者帶來麻煩,只能儘可能的補上已知的。

參考資料

本文為原創文章,可能會經常更新知識點以及修正一些錯誤,因此轉載請保留原出處,方便溯源,謝謝合作

本文地址:http://www.iamaddy.net/2016/07/emoji-unicode-parser/

想要打賞?你的鼓勵是我前進的動力!addy打賞二維碼