iOS的emoji表情在數據庫不支持UTF-8格式的處理

前言

最近遇到蘋果手機自帶的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表情轉成實體字符都能顯示,只有最基本常用的幾個表情才能利用實體字符顯示出來,如果誰有更好的方法請告之一下,畢竟分享是一個很有趣的事情,大家共同進步,探討,才能接觸更多的東西,學習瞭解更多的東西呀

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章