在開發中突然需要傳Emoji,然而直接傳的話會報錯,而之前開發時又沒接觸夠Emoji,是以打算好好研究一下。
1.Emoji的形式
我想先列印出來看看Emoji是怎麼樣的,我就設斷,看看輸入Emoji之後的字元串是怎樣的,結果發生了十分有意思的事情。
在調試監聽的時候顯示的是豆腐塊
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcuEGOmdTMhRDM2gjN3UDZ4UTO0EWOwU2N0kzY2UTYkFzNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.png)
但是編譯器裡面又能顯示圖
再試試在Log中列印,直接就不顯示
做到這裡,已經不禁讓我懷疑人生,我發現我對String一無所知,瞬間真的有一種不知道要怎麼弄的感覺。
如果哪位大神知道,請告訴我為什麼String顯示Emoji時會這樣,謝謝。
雖然我不知道Emoji在String中到底是怎麼樣的,但是我可以用charAt()方法去檢視它的位址,發現charAt()後列印出這個(我用了另一個Emoji)
實在看不出,再試試charArray
CN是中國圖示的emoji
最後得到的結果是
看得出分割時一般會把一個表情分割成2個char,國旗分割成4個,還有一個的,也看不出什麼。
這什麼玩意,還是不知道,上網查了下,這個叫Unicode 編碼,這就很有意思了,那我就去看看編碼的一些基礎的知識。
2.編碼
我就算沒認真學過,都知道有個編碼叫utf-8,那它和Unicode 編碼有什麼關系呢。
1個位元組為8位,就是說1個位元組可以用8位二進制來表示。而8位二進制一共有256種情況,也就是2的8次方。
是以剛開始就出現了ASCII碼,它用每個情況表示一個符号,ASCII 碼一共定義了 128 個字元。
但是想想,世界上這麼多種符号,僅僅英文的話ASCII 碼是能解決,但是漢字都不止256種了,是以産生了Unicode 編碼,它就相當是ASCII 的一個擴充,但是,有會出現了一些問題,是以出現了UTF-8編碼(我這隻是簡單的說)就當是規範了Unicode 編碼。
是以Emoji得到的是Unicode編碼,那麼我就猜測一下為什麼在AS中有時出現亂碼,有時出現圖案,因為在debug中在編輯器裡面的是展示Unicode碼的,是以能正常顯示圖檔,而Logcat中的編碼方式是utf-8,是以顯示亂碼。
不管怎麼樣,關鍵是這個Edittext.toString()得到的String是不是有Emoji的啊
既然列印和打斷點不行,那我就隻能畫點時間搞個Demo了。
我做兩個Edittext和一個Button,點選按鈕時從第一個Edit擷取String然後顯示到第二個Edit
從結果可以看出,String裡面是有包含Emoji的隻是不能正常列印出來而已。
3.上傳到伺服器
既然能保證String含有Emoji,那麼下一步就是怎麼上傳到伺服器,直接把這個String上傳到伺服器是會報錯的。
(1)轉成Base64
先把字元串轉成Base64再上傳,這是我在網上看到的一篇文章,先測試下轉碼後再解碼能不能得到之前的形式。
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String str = edtUp.getText().toString();
// 轉碼
String str_count= Base64.encodeToString(str.getBytes(),Base64.DEFAULT);
// 解碼
String str2 = new String(Base64.decode(str_count.getBytes(), Base64.DEFAULT));
edtDown.setText(str2);
}
});
可以看出可以使用Base64轉碼和解碼是能成功得到Emoji的。轉之後就是一個字元串,資料是能儲存的,那接下來我就試試能不能把Emoji上傳到資料庫然後在傳回正常顯示。
測試中......測試内容保密......
最後得到結果并展示到textview
可以看出這樣的做成是可以的,就不用再寫什麼先轉換再拼接了。
4.屏蔽
直接上傳emoji會出錯,據說是因為
那這樣的話,解決這個的問題其實還是資料庫去改進,但是......你覺得你說一句“這個是背景的問題,你們來改”,背景人員就會改嗎?他隻會說“你們前端先想辦法解決一下。”沒錯,受欺負的永遠是前端,那怎麼辦,那我們隻好想辦法屏蔽咯。
(1)網上有很多判斷的方法,但是我真的不敢用,有些評論說某些不完整,搞得我都不知道哪些是能用的,哪些是判斷不完整的。
但是我又找不到其它解決的辦法,總覺得屏蔽真麻煩,最直接的辦法還是背景給改了,但是人家肯定不願意弄,那我就貼上代碼(真的很擔心這個判斷會不會又漏)
/**
* 屏蔽emoji
*/
public static String deleteEmoji(String str){
StringBuffer sb = new StringBuffer();
char[] charArray = str.toCharArray();
for (int i = 0; i < charArray.length; i++) {
if (!isEmojiCharacter(charArray[i])) {
sb.append(charArray[i]);
}
}
return sb.toString();
}
/**
* todo 這是網上找的判斷區間,不知道完不完整,暫時先用
* @param codePoint
* @return
*/
private static boolean isEmojiCharacter(char codePoint) {
return !((codePoint == 0x0) ||
(codePoint == 0x9) ||
(codePoint == 0xA) ||
(codePoint == 0xD) ||
((codePoint >= 0x20) && (codePoint <= 0xD7FF)) ||
((codePoint >= 0xE000) && (codePoint <= 0xFFFD)) ||
((codePoint >= 0x10000) && (codePoint <= 0x10FFFF)));
}
這樣操作就能得到屏蔽表情的字元串。
5.總結
關于emoji我是第一次嘗試,這回主要做的任務是怎麼将emoji傳到背景并正常擷取顯示。表面上我是實作這個功能了,為什麼說是表面上呢,因為我傳的是Base64,如果真要這麼做的話,必須和所有端都統一,不然你傳Base64,其它端不解碼展示Base64那就很麻煩。
我想真正尋求的最優解是我這傳的是字元串,别的機子要是能正常顯示就顯示,不能正常顯示就隐藏,但是發現目前我還真不知道要怎麼弄,直接傳的String背景是無法接收的,好像是因為資料庫是3位而emoji大部分都是4位。
還有一點就是自己寫一個Emoji頁面來展示這個沒做,現在用的Emoji是輸入法提供的,但是有些APP會有自己弄的Emoji頁面,這個之後再說吧,總之這次最大的收獲就是基本認識了Emoji,有種一層迷霧散開的感覺,雖然并沒解決最根本的需求問題,但也不虧。
補充
1.開源架構
之後我又發現一個開源的emoji操作的架構
https://github.com/vdurmont/emoji-java這個架構的API還是挺好了解的,就是那個判斷字元串中是否包含emoji的判斷沒用,但是可以用擷取emoji資料取長度來判斷
List<String> emojis = EmojiParser.extractEmojis(str);
if (emojis.size() > 0) {
......
}
2.使用屏蔽的場景
上面我已經講了在資料庫不支援的情況怎麼上傳emoji,現在我打算補充下屏蔽emoji的使用場景。
(1)比如輸入名稱/标題等等這些場景如果輸入emoji的話,就好就是提示使用者無法輸入特殊符号(仿美團的做法)
(2)比如評論,回複這些長的内容輸入emoji而要屏蔽的話,可以在上傳時候删除掉其中的emoji,用我發的架構的做法就是
EmojiParser.removeAllEmojis(str)