前言
最近遇到蘋果手機自帶的emoji表情的處理問題,由於我們的數據庫編碼是GBK編碼,而蘋果的鍵盤自帶的emoji表情,蘋果系統的編碼格式是UTF8編碼,所以在把emoji表情存到GBK編碼的數據庫的就會出現亂碼的現象,這事非常坑爹的事情。但是還有更坑的,由於我們的emoji表情不是有我們客戶端來處理的,其實要是我們客戶端處理的話很簡單,就是把emoji表情處理成相應的唯一字符串,然後存進數據庫,字符串GBK編碼的數據庫肯定可以存。然後我們展示的再處理回來就好,完全我們客戶端就可以操作。坑爹的就是,我們傳的emoji表情是要給html5去展示,這就存在問題了。
1.如何從一段文字提取emoji表情
下面我給出一個方案,我們知道emoji表情本質就是字符串,是字符串就會有長度,而emoji表情的字符串的長度有2,4,7,3等等,未來隨着emoji表情的擴充可能說不定一個emoji表情的長度大於10都有可能,所以我們來遍歷一段含有emoji表情的字符串的問題,來檢查出有沒有emoji表情是很不理想的選擇,雖然可能for循環遍歷也可能弄出來,但這可能需要花費大量的時間和精力去完成,不過所幸的是,蘋果給我們用了一個好的遍歷的方法
檢測表情的輸入
- (NSString *)stringContainsEmoji:(NSString *)string
{
__block BOOL returnValue = NO;
__block NSString *tempStr = @"";
[string enumerateSubstringsInRange:NSMakeRange(0, [string length])
options:NSStringEnumerationByComposedCharacterSequences
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
NSString *tempEmoji = @"";
const unichar high = [substring characterAtIndex: 0];
*** Surrogate pair (U+1D000-1F9FF)***
if (0xD800 <= high && high <= 0xDBFF) {
const unichar low = [substring characterAtIndex: 1];
const int codepoint = ((high - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000;
if (0x1D000 <= codepoint && codepoint <= 0x1F9FF){
returnValue = YES;
tempEmoji = [self getEmojiToShijinZhi:substring];
}
***Not surrogate pair (U+2100-27BF)***
} else {
if (0x2100 <= high && high <= 0x27BF){
returnValue = YES;
tempEmoji = [self getEmojiToShijinZhi:substring];
}
}
if (returnValue == YES) {
tempStr = [tempStr stringByAppendingString:tempEmoji];
}else{
tempStr = [tempStr stringByAppendingString:substring];
}
returnValue = NO;
}];
return tempStr;
}
上面的* Surrogate pair (U+1D000-1F9FF)和*Not surrogate pair (U+2100-27BF)應該是說明emoji表情的uinicode編碼範圍。
我是參考這個簡書作者: [iOS]檢測字符串中是否包含emoji表情
2.emoji表情轉化成實體字符
實體字符就是emoji表情可以不用做任何處理就可以顯示出來是不是很方便,但是它有個很大毛病,不是所有的表情都支持的,因爲的蘋果自帶的emoji表情一直在擴充,但是對應的實體字符不一定跟上腳步,所以emoji表情也是轉化成實體字符也是支持部分。
我也是參考一位樓主的文章: 移動前端手機輸入法自帶emoji表情字符處理
上面的鏈接說明的很清楚,但是沒有說明怎麼把emoji表情轉化成uinicode編碼格式的字符串,uinicode字符串編碼再去取十進制的字符,再然後前面加 &# 就可以了,但是我要說是轉化成uinicode編碼,我在網上查看到這個
- (NSString *)getEmojiToShijinZhi:(NSString *)text{
NSString *hexstr = @"";
for (int i = 0; i < [text length] / 2 && ([text length] % 2 == 0) ; i++)
{
// three bytes
if (([text characterAtIndex:i*2] & 0xFF00) == 0 ) {
hexstr = [hexstr stringByAppendingFormat:@"%1X%1X",[text characterAtIndex:i*2],[text characterAtIndex:i*2+1]];
}else{// four bytes
hexstr = [hexstr stringByAppendingFormat:@"%1X",MULITTHREEBYTEUTF16TOUNICODE([text characterAtIndex:i*2],[text characterAtIndex:i*2+1])];
}
}
LYNSLog(@"(unicode) [%@]",hexstr);
if (![hexstr isEqualToString:@""]) {
NSString * temp10 = [NSString stringWithFormat:@"%lu",strtoul([hexstr UTF8String],0,16)];
LYNSLog(@"心跳數字 10進制 %@",temp10);
//轉成數字
int cycleNumber = [temp10 intValue];
LYNSLog(@"心跳數字 :%d",cycleNumber);
return [NSString stringWithFormat:@"&#%d",cycleNumber];
}
return hexstr;
}
但是這個有個很大的問題是emoji表情的字符串長度是奇數的話就沒法轉碼,我也不知道是那個樓主的特意寫的呢,還是其他的原因,
其實最主要就是
hexstr = [hexstr stringByAppendingFormat:@”%1X%1X”,[text characterAtIndex:i*2],[text characterAtIndex:i*2+1]];
這個%1X就是打印十六進制的,而uinicode就是十六進制的,所以老鐵沒毛病呀,哈哈,Unicode百度百科 這裏就是原因。
所以打印十六進制前面加個U+就是uinicode的表示方法
3.總結
其實他的這個方案也不是解決所有的emoji表情轉成實體字符都能顯示,只有最基本常用的幾個表情才能利用實體字符顯示出來,如果誰有更好的方法請告之一下,畢竟分享是一個很有趣的事情,大家共同進步,探討,才能接觸更多的東西,學習瞭解更多的東西呀