app應用中文字夾帶表情是個很常見的現象。甚至一些40多歲的大叔級使用者,也喜歡在自己的昵稱中夾帶表情,在産品營運後發現這個現象,徹底颠覆了我的世界觀。
在背景處理表情的時間,我遇到過下面3個問題:
表情的utf8編碼,有時是有4個位元組的,是以在一般的utf編碼是沒法存儲的。
在網上看到一個常用的解決方案,是把mysql更新到5.5,然後把字元編碼改為utf8mb4_general_ci。
但實際情況是,有可能在以前的app版本中不需要支援表情,這時系統已經營運了一段時間了,這時才把mysql更新并遷移資料,需要很高的運維成本,同時具備一定的風險,例如,遷移前的不同mysql版本間需要資料同步,保證資料的一緻性;遷移過程中可能出現意想不到的事情,造成服務停止。
但在實踐中,我發現了還有一個方法,适用于mysql 5.1,就是把含有表情的那個字段的類型變為blob, 沒錯,就是用二進制存儲,這樣就能比較少的改動mysql。
很多時候,如果文字中夾帶表情,那麼這些文字的處理就會出現問題,例如,如果一個使用者的昵稱帶有表情,那麼我怎麼把這個昵稱轉換為拼音呢?在推送apns過程中,如果推送的文字中夾帶表情,推送到app端後也會顯示亂碼。
在app後端,存在着大量要處理文字中夾帶表情的需求。我遇到了這個問題,先是找到了 https://github.com/iamcal/php-emoji這個轉換表情的類庫,但發現這個類庫不支援ios6後新增的表情,最後沒辦法了,我寫了個抓取程式,把 http://punchdrunker.github.io/iOSEmoji/table_html/ios6/index.html中ios6後新增的表情抓取出來,并寫了個新的類庫并開源了 https://github.com/newjueqi/converemojitostr,這個類庫的作用就是把文字中夾帶的表情替換為一個特殊的字元(預設是"#")。
openfire中,如果發送某些特殊的字元(例如一些表情符合),會斷開xmpp的連接配接,經查,是由以下的代碼問題引起的:
src\java\org\jivesoftware\openfire\net\MXParser.java
protected char more() throws IOException, XmlPullParserException {
final char codePoint = super.more(); // note - this does NOT return a codepoint now, but simply a (single byte) character!
if ((codePoint == 0x0) || // 0x0 is not allowed, but flash clients insist on sending this as the very first character of a stream. We should stop allowing this codepoint after the first byte has been parsed.
(codePoint == 0x9) ||
(codePoint == 0xA) ||
(codePoint == 0xD) ||
((codePoint >= 0x20) && (codePoint <= 0xD7FF)) ||
((codePoint >= 0xE000) && (codePoint <= 0xFFFD)) ||
((codePoint >= 0x10000) && (codePoint <= 0x10FFFF))) {
return codePoint;
}
throw new XmlPullParserException("Illegal XML character: " + Integer.parseInt(codePoint+"", 16));
}
由于在這裡把特殊的字元當成了一個異常,是以openfire會斷開連接配接。
解決方法:
@Override
protected char more() throws IOException, XmlPullParserException {
final char codePoint = super.more(); // note - this does NOT return a codepoint now, but simply a (single byte) character!
if ((codePoint == 0x0) || // 0x0 is not allowed, but flash clients insist on sending this as the very first character of a stream. We should stop allowing this codepoint after the first byte has been parsed.
(codePoint == 0x9) ||
(codePoint == 0xA) ||
(codePoint == 0xD) ||
//fix some emotion
((codePoint >= 0x20) && (codePoint <= 0xFFFD)) ||
((codePoint >= 0x10000) && (codePoint <= 0x10FFFF))) {
return codePoint;
throw new XmlPullParserException("Illegal XML character: " + Integer.parseInt(codePoint+"", 16));
}
如何聯系我:【萬裡虎】www.bravetiger.cn
【QQ】3396726884 (咨詢問題100元起,幫助解決問題500元起)
【部落格】http://www.cnblogs.com/kenshinobiy/