js解析emoji表情

Emojiphp

公司的產品以前只有網頁端,並無提供emoji表情,以後將某個模塊整合到app中,裏面有個評論功能,在手機端能夠輸入emoji,顯示的時候是空白,說明數據庫並無存儲成功,查閱資料後得知emoji是四個字節,而mysql5.5.3前的版本utf8編碼最多隻支持3個字節。css

js解析emojihtml

先須要瞭解幾個概念,js的編碼方式、utf1六、unicodemysql

1.JavaScript語言採用Unicode字符集,可是隻支持一種編碼方法ucs-2jquery

2.utf16編碼git

utf16是ucs-2的超集github

3.Unicode只規定了每一個字符的碼點,到底用什麼樣的字節序表示這個碼點,就涉及到編碼方法sql

因爲JavaScript只能處理UCS-2編碼,形成全部字符在這門語言中都是2個字節,若是是4個字節的字符,會看成兩個雙字節的字符處理。JavaScript的字符函數都受到這一點的影響,沒法返回正確結果數據庫

emoji表情是由utf16編碼的,多是2個字節,也多是四個字節後端

這裏的解析我用的是twemoji庫,原理是將utf16編碼轉爲unicode的十六機制並以此十六進制做爲emoji圖片的命名

這裏的關鍵是如何將utf16轉爲unicode十六進制

UTF-16的轉碼公式

將unicode轉爲utf16,官方給了公式

Unicode碼點轉成UTF-16的時候,首先區分這是基本平面字符(2字節),仍是輔助平面字符(4字節)。若是是前者,直接將碼點轉爲對應的十六進制形式,長度爲兩字節。

若是是輔助平面字符,Unicode 3.0版給出了轉碼公式。

H= Math.floor((c-0x10000)/0x400)+0xD800 //高位

L = (c-0x10000)%0x400+0xDC00 //低位

將utf16轉爲unicode則是知道H,L,求c,學過方程組的應該都會解答吧

給出上述轉化的函數

 1 /*unicode編碼範圍 2字節0x0000-0xffff
 2       四字節爲0x010000-0x10ffff
 3       U+D800到U+DFFF 爲空段
 4       因爲JavaScript只能處理UCS-2編碼,形成全部字符在這門語言中都是2個字節,若是是4個字節的字符,會看成兩個雙字節的字符處理
 5      */
 6   function toCodePoint(unicodeSurrogates, sep) {
 7     var
 8       r = [],
 9       c = 0,
10       p = 0,
11       i = 0;
12     while (i < unicodeSurrogates.length) {
13       c = unicodeSurrogates.charCodeAt(i++);//返回位置的字符的 Unicode 編碼
14       
15       if (p) {
16         r.push((0x10000 + ((p - 0xD800) << 10) + (c - 0xDC00)).toString(16)); //計算4字節的unicode
17         p = 0;
18       } else if (0xD800 <= c && c <= 0xDBFF) { 
19         p = c; //若是unicode編碼在oxD800-0xDBff之間,則須要與後一個字符放在一塊兒
20       } else {
21         r.push(c.toString(16)); //若是是2字節,直接將碼點轉爲對應的十六進制形式
22       }
23     }
24     return r.join(sep || '-');
25   }
View Code

 

emojipicker

頁面上選擇emoji表情,插入input,發送給後端時須要轉爲utf16

這裏我用的庫是jquery-emoji-picker,這裏遇到一個問題,它的css中背景圖片是datauri,我又須要兼容ie6,我須要將它的樣式文件重寫,並將圖片保存起來。若是數量少,我會手動改下,結果一看,855個,果斷寫腳本

 1 <?php
 2 function formatData($str){
 3     $data=array();
 4     $reg='/^\.emoji-([^\{]+)\s+\{background-size:100% !important; background-image: url\(\'(.+)\'\);\}/'; //匹配樣式
 5     preg_match($reg, $str, $matches);
 6     $data=array('filename'=>$matches[1].'.png','base64'=>substr($matches[2],22),'name'=>$matches[1]);
 7     return $data;
 8 }
 9 function basetopng($base64,$filename){
10     $str=base64_decode($base64);
11     file_put_contents('images/'.$filename, $str);
12 }
13 $css_file = 'emojipicker.css';
14 $start = 0;        // 從第0行開始讀取
15 $num = 855;                // 讀取855行
16 $data = array();
17 $str='';//生成css文件
18 $spl_object = new SplFileObject($css_file, 'rb');
19 $spl_object->seek($start);
20 while ($num-- && !$spl_object->eof()) {
21     $tmp = $spl_object->fgets();
22     $tmpData=formatData($tmp);
23     $filepath='../images/'.$tmpData['filename'];
24     $str.=".emoji-{$tmpData['name']} { background-size:100% !important; background-image: url('/Public/plugin/emojipicker/images/{$tmpData['filename']}');}\n"; 
25     $spl_object->next();
26 }
27 file_put_contents('emojipicker.ff.css', $str);
28 
29 ?>
View Code

 

 點擊icon得到emoji的name,將name轉化爲‘<微笑>’字樣插入input,提交給後臺的時候再將'<微笑>'字樣轉化爲utf16(先轉化爲unicode,在轉化爲utf16)

我又跑去微信界面盜了點資源過來,領導說作成微信相似就行了,原來的jquery.emojipicker.a.js中的數據結構是

{
    "name": "sunny",
    "unicode": "2600",
    "shortcode": "sunny",
    "description": "BLACK SUN WITH RAYS",
    "category": "thing"
  }

我須要給它加點東西,變成這樣

{
        "name": "sunny",
        "unicode": "2600",
        "shortcode": "sunny",
        "desc": "<太陽>",
        "title": "太陽",
        "category": "thing"
}

而微信的數據結構是這樣 {"<太陽>" : "2600"},應該怎麼對應,unicode與wx的value相等,以這個爲基準

 1 var  a=[],//須要的微信表情unicode
 2                     wxemojis=window.gQQFaceMap,
 3                     b=[];//格式化數據,添加desc,title
 4                for(var i in wxemojis){
 5                     if(wxemojis[i].length>3){
 6                          if(a.indexOf(wxemojis[i]) < 0){
 7                               a[a.length]=wxemojis[i];
 8                               b[b.length]={
 9                                    'unicode':wxemojis[i],
10                                    'desc':i,
11                                    'title':i.replace(/(<|>)/g,'')
12                               };
13                          }
14                     }
15                }
16 var myEmojis=[];//我須要的表情數組
17 for(var i in emojis){
18      var tmpIndex=a.indexOf(emojis[i].unicode.toLowerCase());
19      if(tmpIndex > -1){
20           myEmojis[myEmojis.length]={
21                "name":emojis[i].name,
22                "unicode":emojis[i].unicode,
23                "shortcode":emojis[i].shortcode,
24                "desc":b[tmpIndex].desc,
25                "title":b[tmpIndex].title,
26                "category":emojis[i].category
27                          }
28      }
29 }
30 console.log(JSON.stringify(myEmojis));   
View Code

 生成了本身的表情數組。

將中文字樣轉爲utf16,傳給後端

 1 function toUnicode(code) {
 2     var codes = code.split('-').map(function(value, index) {
 3       return parseInt(value, 16);
 4     });
 5     return String.fromCodePoint.apply(null, codes);
 6   }
 7 
 8   if (!String.fromCodePoint) {
 9     // ES6 Unicode Shims 0.1 , © 2012 Steven Levithan http://slevithan.com/ , MIT License
10     String.fromCodePoint = function fromCodePoint () {
11       var chars = [], point, offset, units, i;
12       for (i = 0; i < arguments.length; ++i) {
13         point = arguments[i];
14         offset = point - 0x10000;
15         units = point > 0xFFFF ? [0xD800 + (offset >> 10), 0xDC00 + (offset & 0x3FF)] : [point];
16         chars.push(String.fromCharCode.apply(null, units));
17       }
18       return chars.join("");
19     }
20   }
21   function htmlEncode(a) {
22   return a && a.replace ? a.replace(/&/g, "&amp;").replace(/\"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\'/g, "&#39;") : a
23 }
24   function afterEncodeEmoji(str){
25     var faceMap={"<笑臉>":"1f604","<開心>":"1f60a","<大笑>":"1f603","<熱情>":"263a","<眨眼>":"1f609","<色>":"1f60d","<接吻>":"1f618","<親吻>":"1f61a","<臉紅>":"1f633","<露齒笑>":"1f63c","<滿意>":"1f60c","<戲弄>":"1f61c","<吐舌>":"1f445","<無語>":"1f612","<得意>":"1f60f","<汗>":"1f613","<失望>":"1f640","<低落>":"1f61e","<呸>":"1f616","<焦慮>":"1f625","<擔憂>":"1f630","<震驚>":"1f628","<悔恨>":"1f62b","<眼淚>":"1f622","<哭>":"1f62d","<破涕爲笑>":"1f602","<暈>":"1f632","<恐懼>":"1f631","<心煩>":"1f620","<生氣>":"1f63e","<睡覺>":"1f62a","<生病>":"1f637","<惡魔>":"1f47f","<外星人>":"1f47d","<心>":"2764","<心碎>":"1f494","<丘比特>":"1f498","<閃爍>":"2728","<星星>":"1f31f","<歎號>":"2755","<問號>":"2754","<睡着>":"1f4a4","<水滴>":"1f4a6","<音樂>":"1f3b5","<火>":"1f525","<便便>":"1f4a9","<強>":"1f44d","<弱>":"1f44e","<拳頭>":"1f44a","<勝利>":"270c","<上>":"1f446","<下>":"1f447","<右>":"1f449","<左>":"1f448","<第一>":"261d","<強壯>":"1f4aa","<吻>":"1f48f","<熱戀>":"1f491","<男孩>":"1f466","<女孩>":"1f467","<女士>":"1f469","<男士>":"1f468","<天使>":"1f47c","<骷髏>":"1f480","<紅脣>":"1f48b","<太陽>":"2600","<下雨>":"2614","<多雲>":"2601","<雪人>":"26c4","<月亮>":"1f319","<閃電>":"26a1","<海浪>":"1f30a","<貓>":"1f431","<小狗>":"1f429","<老鼠>":"1f42d","<倉鼠>":"1f439","<兔子>":"1f430","<狗>":"1f43a","<青蛙>":"1f438","<老虎>":"1f42f","<考拉>":"1f428","<熊>":"1f43b","<豬>":"1f437","<牛>":"1f42e","<野豬>":"1f417","<猴子>":"1f435","<馬>":"1f434","<蛇>":"1f40d","<鴿子>":"1f426","<雞>":"1f414","<企鵝>":"1f427","<毛蟲>":"1f41b","<章魚>":"1f419","<魚>":"1f420","<鯨魚>":"1f433","<海豚>":"1f42c","<玫瑰>":"1f339","<花>":"1f33a","<棕櫚樹>":"1f334","<仙人掌>":"1f335","<禮盒>":"1f49d","<南瓜燈>":"1f383","<鬼魂>":"1f47b","<聖誕老人>":"1f385","<聖誕樹>":"1f384","<禮物>":"1f381","<鈴>":"1f514","<慶祝>":"1f389","<氣球>":"1f388","<CD>":"1f4bf","<相機>":"1f4f7","<錄像機>":"1f3a5","<電腦>":"1f4bb","<電視>":"1f4fa","<電話>":"1f4de","<解鎖>":"1f513","<鎖>":"1f512","<鑰匙>":"1f511","<成交>":"1f528","<燈泡>":"1f4a1","<郵箱>":"1f4eb","<浴缸>":"1f6c0","<錢>":"1f4b2","<藥丸>":"1f48a","<橄欖球>":"1f3c8","<籃球>":"1f3c0","<足球>":"26bd","<棒球>":"26be","<高爾夫>":"26f3","<獎盃>":"1f3c6","<入侵者>":"1f47e","<唱歌>":"1f3a4","<吉他>":"1f3b8","<比基尼>":"1f459","<皇冠>":"1f451","<雨傘>":"1f302","<手提包>":"1f45c","<口紅>":"1f484","<戒指>":"1f48d","<鑽石>":"1f48e","<咖啡>":"2615","<啤酒>":"1f37a","<乾杯>":"1f37b","<雞尾酒>":"1f377","<漢堡>":"1f354","<薯條>":"1f35f","<意麪>":"1f35d","<壽司>":"1f363","<麪條>":"1f35c","<煎蛋>":"1f373","<冰激凌>":"1f366","<蛋糕>":"1f382","<蘋果>":"1f34f","<飛機>":"2708","<火箭>":"1f680","<自行車>":"1f6b2","<高鐵>":"1f684","<警告>":"26a0","<旗>":"1f3c1","<男人>":"1f6b9","<女人>":"1f6ba","<O>":"2b55","<X>":"274e","<商標>":"2122"};
26     var unicodeStr=str.replace(/<.*?>/g,function(a){
27       if(faceMap[a]){
28         return toUnicode(faceMap[a]);
29       }else{
30         return a;
31       }
32       //  return a?toUnicode(faceMap[a]):'';
33     });
34     return htmlEncode(unicodeStr);
35   }

 已經基本完成我須要的功能了(兼容至ie6+)。

結語

 

獻上本人拙劣的demo(css不行)

[emoji picker demo](https://ceau.github.io/emojipicker/demo.html)

相關文章
相關標籤/搜索