1. 程式人生 > >emoji處理方式大起底

emoji處理方式大起底

emoji資料

今天研究了emoji,挺有意思,資料挺多,摘要一些資訊給大家分享,也算是自己記錄學習。

emoji介紹

Emoji (絵文字,詞義來自日語えもじ,e-moji,moji在日語中的含義是字元)是一套起源於日本的12x12畫素表情符號,由慄田穣崇(Shigetaka Kurit)創作,最早在日本網路及手機使用者中流行,自蘋果公司釋出的iOS 5輸入法中加入了emoji後,這種表情符號開始席捲全球,目前emoji已被大多數現代計算機系統所相容的Unicode編碼採納,普遍應用於各種手機簡訊和社交網路中。近期,更是有不少網友用emoji圖案玩猜字遊戲,享受這種表情文化帶來的樂趣。

關於emoji的發音:很多人第一眼見到emoji便會下意識將其誤讀作“一磨嘰”,其實不然,emoji音譯過來大概讀作“誒磨嘰”,當中“e”的發音頗似字母abc的a的發音。

最初日本的三大電信運營商各自有不同的字元定義,分別是DoCoMo、KDDI和Softbank。隨著iOS內建了Softbank的版本,emoji在全球範圍內風靡(iOS5版本以前)。而Google又自己定義了一套emoji字元。iOS5以後,apple採用了unicode定義的emoji字元(iOS5版本以後)。

unicode定義的emoji是四個字元,softbank為3個字元,emoji的四個字元從儲存到展示對應沒有做過考慮的系統來說,簡直就是災難。

面臨問題:

插入Emoji表情,儲存到資料庫時報錯:

SQLException: Incorrect string value: '\xF0\x9F\x98\x84' for column 'review' at row 1

UTF-8編碼有可能是兩個、三個、四個位元組。Emoji表情是4個位元組,而Mysql的utf8編碼最多3個位元組,所以資料插不進去。

解決方案:過濾解決

把emoji直接過濾掉,簡單方便有效。雖然損失了幾個emoji字元,但強過不至於導致整條記錄丟失。

  1. publicstatic String removeNonBmpUnicode(String str) {    
  2.    if (str == null) {    
  3.        return null;    
  4.    }    
  5.    str = str.replaceAll("[^\\u0000-\\uFFFF]""");    
  6.   return str;    
  7. }    
這種方案能預防能解決問題,並且還能是程式更加健壯,但是從使用者體驗上來說並不好,使用者發的emoji表情丟了,看下面的解決方案。

解決方案:將Mysql的編碼從utf8轉換成utf8mb4。

從 MySQL 5.5.3 開始,MySQL 支援一種 utf8mb4 的字符集,這個字符集能夠支援 4 位元組的 UTF8 編碼的字元。 utf8mb4 字符集能夠完美地向下相容 utf8 字串。在資料儲存方面,當一個普通中文字元存入資料庫時仍然佔用 3 個位元組,在存入一個 Unified Emoji 表情的時候,它會自動佔用 4 個位元組。所以在輸入輸出時都不會存在亂碼的問題了。

要使用 MySQL 的這個特性,首先需要把 MySQL 升級到 5.5.3 以上的版本。

其次,需要修改資料結構中的字符集為 utf8mb4 ,如 utf8mb4_general_ci 。由於 utf8mb4 是 utf8 的超集,從 utf8 升級到 utf8mb4 不會有任何問題,直接升級即可;如果從別的字符集如 gb2312 或者 gbk 轉化而來,一定要先備份資料庫。

然後,修改 MySQL 的配置檔案 /etc/my.cnf,修改連線預設字符集為 utf8mb4 ,如果是自己寫的 PHP 指令碼,也可以在連線資料庫以後首先執行一句 SQL: SET NAMES utf8mb4;。這時候,PHP 應該就可以正常儲存 Emoji 到資料庫了。

這種方式可能帶來的問題:

儲存:在資料表中,對於變長的欄位(如VARCHAR2,TEXT),utf8mb4最大可儲存的字元可能少於utf8系列的collation;在索引中,對於文字型別的欄位,utf8mb4可索引的字元少於utf8系列的collations。如InnoDB的索引最多使用767位元組。如果使用utf8mb4,每一個字元都會預留4位元組做索引,而utf8則預留3位元組。故此前者是191個字元,後者是255個字元。。

效能:由於以上原因,加上字符集大,utf8mb4的效能可能比utf8系列的collations低,可以參考stackoverfolow上的一個測試結果:http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci,差異不是特別大。

運維:如果一個大的環境內,如果其他的資料庫都是utf8模式,把其中某個庫設定為utf8mb4模式,在後續交接運維可能會造成問題,遺留下坑。

上下游:資料庫支援unicode的emoji儲存,上下游不一定支援。比如mysql客戶端驅動(低版本的jdbc就不行)可能不支援utf8mb4,或者DDL的中介軟體不支援utf8mb4。web端處理utf8mb4字元展示,這些都有可能影響emoji的儲存活著展示。

從上面的資訊,從資料庫層面如果不是特別看重儲存,效能,運維並能解決上下游的問題,資料庫是完全可以支援emoji的,但是有個新問題沒有解決,emoji在iOS上展示OK,andriod裝置如何展示emoji表情?

解決方案:轉義解決

1:unicode emoji轉softbank的emoji。

我們知道unicode emoji是4個位元組,softbank定義的emoji佔用3個位元組儲存,通過emoji for php http://code.iamcal.com/php/emoji/,我們可以把unicode的emoji方式轉換為softbank方式,從而實現不修改資料庫,就能儲存emoji,相對於資料庫層面的解決問題的方式,動作要小的多,並且也不會有效能,運維等方面的問題。但是有個不可避免的問題是,Softbank方式已經不再維護,所以新增加的emoji表情,Softbank中都沒有,會造成部分emoji表情丟失的情況。

2:ubb

UBB程式碼是HTML(標準通用標記語言下的一個應用)的一個變種,是Ultimate Bulletin Board (國外的一個BBS程式)採用的一種特殊的TAG。您也許已經對它很熟悉了。UBB程式碼很簡單,功能很少,但是由於其Tag語法檢查實現非常容易,所以不少網站引入了這種程式碼,以方便網友使用顯示圖片/連結/加粗字型等常見功能。

比如emoji的太陽符號,他的unicode emoji編碼為U+2600,在存入資料庫時,可以把它轉換成  UBB 程式碼 [emoji]2600[/emoji] 儲存,讀取的時候,可以轉換回來。當然針對不同的裝置,比如andriod我們可以轉義成andriod可以處理的emoji符號。

這種轉移,可以很好解決iOS和Andriod顯示emoji的問題,但是還存在幾個問題。

1:andriod和iOS的emoji並不相同,相同的編碼 可能在iOS上是太陽,而在andriod上是陰天,解決這種問題方式最好做下iOS和andriod下的emoji對映,同時可以在web上通過js轉義處理。

2:效能,採用轉義的方式處理,效能肯定會有所下降,但是可以容忍。

與UBB對應的是html轉義,這種方式,其實和ubb有些類似, 使用 HTML轉義字元 ☀,結果和效能和UBB差不多,從規範化上來說,ubb方式更好一些。

參考資料