2017-11-15 16:59:44 w2865673691 阅读数 1788

emoji就是表情符号,来自日语词汇“絵文字”(假名为“えもじ”,读音即emoji)。

手机操作系统iOS,Android,WindowsPhone;电脑:Windows,Mac OS X均内设Emoji表情;QQ等聊天工具中也添加了emoji表情供用户使用;另外搜狗手机输入法,Google拼音等Android第三方输入法也内置此表情。


mysql存储表情符号会报错如下:
Caused by: java.sql.SQLException: Incorrect string value: '\xF0\x9F\x98\x97\xF0\x9F...' for column 'CONTENT' at row 1


解决方法:

1、数据库,表,字段字符集改成utf8mb4。

2、mysql配置文件修改如下:

 [client] 
default-character-set = utf8mb4 
[mysql] 
default-character-set = utf8mb4 


[mysqld] 
character-set-server = utf8mb4 
collation-server = utf8mb4_unicode_ci 
init_connect='SET NAMES utf8mb4'

注意windows下配置文件叫my.ini,如果没有这个文件就自己创建,一般默认会有一个my-default.ini文件,拷贝一下重命名就行了。

但是jdbc驱动目前不支持utf8mb4,所以连接字符集characterEncoding设置utf8mb4会报错,所以去掉即可:

jdbc:mysql://localhost:3306/test?autoReconnect=true&useUnicode=true

2016-08-04 10:24:02 pengyuan_D 阅读数 1462

如果项目中有评论或者信息恢复的地方,往往会用到emoji,有时候如后台不支持emoji,就会显示乱码错误,我们可以把emoji转成unicode编码或者utf8编码格式传给服务器。当然如果后台服务器接收的时候能做好判断识别最好,我们这边后台是支持的,我仅记录一下方法,以备不时之需。

先定义一个UITextView 并设置代理 

设定一个宏定义,用来判断emoji 

 #define MULITTHREEBYTEUTF16TOUNICODE(x,y) (((((x ^ 0xD800) << 2) | ((y ^ 0xDC00) >> 8)) << 8) | ((y ^ 0xDC00) & 0xFF)) + 0x10000

下面写代理方法实现的内容

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
    NSString *hexstr = @"";
    
    for (int i=0;i< [text length];i++)
    {
        hexstr = [hexstr stringByAppendingFormat:@"%@",[NSString stringWithFormat:@"0x%1X ",[text characterAtIndex:i]]];
    }
    NSLog(@"UTF16 [%@]",hexstr);
    
    hexstr = @"";
    
    long slen = strlen([text UTF8String]);
    
    for (int i = 0; i < slen; i++)
    {
        //fffffff0 去除前面六个F & 0xFF
        hexstr = [hexstr stringByAppendingFormat:@"%@",[NSString stringWithFormat:@"0x%X ",[text UTF8String][i] & 0xFF ]];
    }
    NSLog(@"UTF8 [%@]",hexstr);
    
    hexstr = @"";
    
    if ([text length] >= 2) {
        
        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:@"Ox%1X 0x%1X",[text characterAtIndex:i*2],[text characterAtIndex:i*2+1]];
            }
            else
            {// four bytes
                hexstr = [hexstr stringByAppendingFormat:@"U+%1X ",MULITTHREEBYTEUTF16TOUNICODE([text characterAtIndex:i*2],[text characterAtIndex:i*2+1])];
            }
            
        }
        NSLog(@"(unicode) [%@]",hexstr);
    }
    else
    {
        NSLog(@"(unicode) U+%1X",[text characterAtIndex:0]);
    }
    
    return YES;
}

在输入的时候,会自动把输入内容转成相应的格式。

 

 

如果在有些地方不需要输入emoji表情,可以做相关限制。

我这边用到的是,如果用户输入emoji表情的时候,会给出提示

//是否含有表情
- (BOOL)stringContainsEmoji:(NSString *)string
{
    __block BOOL returnValue = NO;
    
    [string enumerateSubstringsInRange:NSMakeRange(0, [string length])
                               options:NSStringEnumerationByComposedCharacterSequences
                            usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
                                const unichar hs = [substring characterAtIndex:0];
                                if (0xd800 <= hs && hs <= 0xdbff) {
                                    if (substring.length > 1) {
                                        const unichar ls = [substring characterAtIndex:1];
                                        const int uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000;
                                        if (0x1d000 <= uc && uc <= 0x1f77f) {
                                            returnValue = YES;
                                        }
                                    }
                                } else if (substring.length > 1) {
                                    const unichar ls = [substring characterAtIndex:1];
                                    if (ls == 0x20e3) {
                                        returnValue = YES;
                                    }
                                } else {
                                    if (0x2100 <= hs && hs <= 0x27ff) {
                                        returnValue = YES;
                                    } else if (0x2B05 <= hs && hs <= 0x2b07) {
                                        returnValue = YES;
                                    } else if (0x2934 <= hs && hs <= 0x2935) {
                                        returnValue = YES;
                                    } else if (0x3297 <= hs && hs <= 0x3299) {
                                        returnValue = YES;
                                    } else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b || hs == 0x2b50) {
                                        returnValue = YES;
                                    }
                                }
                            }];
    
    return returnValue;
}

通过调用该方法,如果返回的是YES则输入内容含有emoji,反之。



2018-01-23 10:03:00 weixin_34179762 阅读数 3

在某个 iOS 项目中,需要一个服务器来保存一些用户数据,例如用户信息、评论等,我们的服务器端使用了 PHP+MySQL 的搭配。在测试过程中我们发现,用户在 iOS 端里输入了 Emoji 表情提交到服务器以后,PHP 无法在 MySQL 数据库里正确保存,会遇到乱码的问题。下面是原因探析和解决办法。

说起 Emoji 的历史说开去那可谓是源远流长了,这里简要介绍 Emoji 在 iOS 系统中的变迁史。不知道何时起,日本人喜欢发 Emoji 表情图标,于是日本的运营商 DoCoMo、KDDI、SoftBank 推出了自己的 Emoji 字符集。在这些字符集中,一个 Emoji 表情的实际上是一个 UTF8 字符,这点不同于 QQ 或者微信的表情,用户发短信的时候一个 Emoji “图像”只占用了一个字符,那是相当的方便。苹果的 iOS 和 Mac OS X 系统内置了 Apple Color Emoji(Apple 彩色表情符号)的字体用来显示 Emoji 表情,iOS 里有一个 Emoji 输入键盘,可以输入各种 Emoji 表情图标,在 Mac OS X 里使用 Option + Command + T 调出输入键盘里选择“表情符号”输入,Mac OS X 里的字体文件位于 /System/Library/Fonts/Apple Color Emoji.ttf。抛开版权因素,把这个文件拷贝到 Windows 的字库文件夹里,Windows 也能支持 Emoji 的显示了。

从技术上说,单个 Emoji 表情实际上是使用 UTF8 编码的一个字符,苹果在 iOS4 开始支持了 Emoji 的显示,当时用的是 SoftBank 的方案。在日本的三家运营商之间,用来表示同一个表情的 UTF8 码并不相同(见对比列表),他们之间要做一个转换才能正确显示。以相同一个表情笑脸为例,SoftBank 表示为 U+E04A,KDDI 则表示为 U+E488

iOS4 的解决方案

不过唯一的好处在于,这时候的每个 Emoji 图标,都是使用 3 字节的 UTF8 字符编码。说句题外话,在刚开始 PHP 开发的时候,大家都知道一个中文在 UTF8 字符集占据 3 个字节。 回到 iOS 和 Web 服务器之间的通信方案,我们可以直接把 iOS 中用户输入的 Emoji 表情,通过 PHP 存入 MySQL 数据库中,如果在 iOS 中展示,直接把数据传递给 iOS,客户端应该就能正确展示表情图标了,如果把用户在 iOS 端输入的表情在 Web 端展示,需要把 Emoji 字符转化为对应的图片(当然支持 Emoji 的 Mac OS X 系统可以通过指定网页 CSS 的 font-family 属性直接显示)。Emoji for PHP 组件能够方便地在各种 Unified、DoCoMo、KDDI、SoftBank、Google 编码之间进行转换。

iOS5 的解决方案

从 iOS5 开始,苹果开始支持标准的 Unified 编码的 Emoji 表情。这其中最大的优点莫过于统一了规格,方便了用户和开发者。但是,Web 开发者在开发网页端的时候就会遇到一些问题,以往直接把 Emoji 表情存储在数据库中现在则会导致乱码。这是由于采用 Unified 标准的单个 Emoji 字符一般为 4 个字节,超过了 MySQL 数据库 utf8 字符集支持的每个字符 3 个字节的限制,存入数据库以后会产生乱码或者破坏数据。

如果说解决该问题,最方便的做法是在存入数据库之前,把每个 Emoji 字符转化为 UBB 代码,或者是其他可辨认的形式,如 HTML 转义字符。还是以太阳符号为例,它的 Unified Emoji 编码为 U+2600,在存入数据库时,可以把它转换成  UBB 代码 [emoji]2600[/emoji] 保存,也可以使用 HTML 转义字符 &#x2600; 储存。如果在 Web 前端展示,用 HTML 转义字符可以直接输出,用 UBB 代码则方便论坛等需要严格安全验证用户输入的地方使用。

还有一种做法你可能也猜到了,采用 SoftBank 方案的单个 Emoji 表情占用 3 个字节,可以直接保存在数据库里,所以可以把 Unified Emoji 转化为 SoftBank Emoji 格式,存储在数据库中就不会有任何问题了。

另外一种方式从 MySQL 自身解决。从 MySQL 5.5.3 开始,MySQL 支持一种 utf8mb4 的字符集,这个字符集能够支持 4 字节的 UTF8 编码的字符。 utf8mb4 字符集能够完美地向下兼容 utf8 字符串。在数据存储方面,当一个普通中文字符存入数据库时仍然占用 3 个字节,在存入一个 Unified Emoji 表情的时候,它会自动占用 4 个字节。所以在输入输出时都不会存在乱码的问题了。要使用 MySQL 的这个特性,首先需要把 MySQL 升级到 5.5.3 以上的版本。其次,需要修改数据结构中的字符集为 utf8mb4 ,如 utf8mb4_general_ci 。由于 utf8mb4 是 utf8 的超集,从 utf8 升级到 utf8mb4 不会有任何问题,直接升级即可;如果从别的字符集如 gb2312 或者 gbk 转化而来,一定要先备份数据库。然后,修改 MySQL 的配置文件 /etc/my.cnf,修改连接默认字符集为 utf8mb4 ,如果是自己写的 PHP 脚本,也可以在连接数据库以后首先执行一句 SQL: SET NAMES utf8mb4;。这时候,PHP 应该就可以正常保存 Emoji 到数据库了。

iOS6 的解决方案

苹果在 iOS6 和 Mac OS X 10.8 中又增加了 300 多个 Emoji 表情,而 SoftBank 编码因为渐渐被历史淘汰,已经没有了相应的升级,所以上文提到的把 Unified Emoji 转化为 SoftBank Emoji 后保存在数据库中的方案已经落伍了。

最终解决方案

说了那么多,最终还是要归纳总结一下解决方法。

从数据库中保存的形态出发,要么用 UBB 或者 HTML 转义字符等替代方法保存,要么用数据库直接存储 Emoji 字符。如果直接保存 Emoji 字符,则必须将 MySQL 升级到 5.5.3 以上并且采用 utf8mb4 字符集。如果用替代方法,则不用升级数据库,不影响现有的服务器,是比较省事的方法。

在用户输入方面,以某著名门户新闻客户端为例,常见的几个平台包括:Web,iOS,安卓等。 Web 端上主要是让用户通过点击图标输入 Emoji 表情,在文本框里可以直接以 UBB 代码[emoji]2600[/emoji] 的形式显示,也要考虑 Mac OS X 或 iOS 移动网页端用户直接通过键盘输入 Emoji 字符,这时候最好在 CSS 里添加 textarea{font-family:"Apple Color Emoji","Arial";} ,以便 Mac OS X 上的 Chrome / Firefox 浏览器用户输入了表情以后能直接显示出来,而不是黑框框。iOS 客户端不必说了,直接让用户使用 iOS 自带的表情键盘即可。至于 Android, Windows Phone 或者黑莓等其他平台,一般要通过第三方的输入法来输入 Emoji 表情。至于用户输入的 Emoji 字符还是 UBB 代码,服务器端应该都要有处理的能力。值得注意的是,可能 SoftBank 等 Emoji 字符集都已经不是主流了,在中国的用户估计很少,但如果你想做一个像微信那么跨国界的 APP,还是不妨加一个转换,首先将各种形式的 Emoji 字符首先转换为 Unified Emoji。

在 Web 端显示方面,出于各平台的兼容性考虑,把 Emoji 表情通过图片输出是最合适的做法。无论在数据库中我们保存的形态是什么,把它转化为图片都需要一个对应表。Emoji for PHP已经实现了 iOS5 的 500 多个表情的支持,但尚未提供 iOS6 新增的 300 多个表情。我虽然已经做了对应关系,但是因为没有整理出代码,暂时没办法放出来。

在 iOS 端显示方面,鉴于用户普遍升级到 iOS5 以上,自然是显示原生支持的 Unified Emoji。在安卓和其他移动平台客户端上,我暂时没有研究过,但估计显示图片是比较好的选择。

参考资料:

2017-11-25 10:44:38 ProgrammerWorking 阅读数 2318

前言

最近遇到苹果手机自带的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表情转成实体字符都能显示,只有最基本常用的几个表情才能利用实体字符显示出来,如果谁有更好的方法请告之一下,毕竟分享是一个很有趣的事情,大家共同进步,探讨,才能接触更多的东西,学习了解更多的东西呀

2016-02-22 17:05:40 gphjl 阅读数 5210

背景

移动设备经常会发生用户发送的内容中包含emoji表情,未经处理,在显示时就是乱码。

解决方案

1.数据库支持:将Mysql的编码从utf8转换成utf8mb4。 

2.匹配出内容中的emoji表情做过滤或替换

/**
 * 表情转换  更新到ios9.2涵盖编码范围
 * @param $str
 * @return mixed
 */
public static function emoji_to_html($str) {
    $regex = '/([0-9|#][\x{20E3}])|[\x{00ae}|\x{00a9}|\x{203C}|\x{2047}|\x{2048}|\x{2049}|\x{3030}|\x{303D}|\x{2139}|\x{2122}|\x{3297}|\x{3299}][\x{FE00}-\x{FEFF}]?|[\x{2190}-\x{21FF}][\x{FE00}-\x{FEFF}]?|[\x{2300}-\x{23FF}][\x{FE00}-\x{FEFF}]?|[\x{2460}-\x{24FF}][\x{FE00}-\x{FEFF}]?|[\x{25A0}-\x{25FF}][\x{FE00}-\x{FEFF}]?|[\x{2600}-\x{27BF}][\x{FE00}-\x{FEFF}]?|[\x{2900}-\x{297F}][\x{FE00}-\x{FEFF}]?|[\x{2B00}-\x{2BF0}][\x{FE00}-\x{FEFF}]?|[\x{1F000}-\x{1F6FF}][\x{FE00}-\x{FEFF}]?|[\x{1F900}-\x{1F9FF}][\x{FE00}-\x{FEFF}]?/u';
    $str = preg_replace_callback($regex,function($matches){
        $str = json_encode($matches[0]);
        $str = '<em data-emoji=' . str_replace('\u', 'em:', $str) . '></em>';
        return $str;
    },$str);
    return $str;
}
从数据库取出后再转回
$string = preg_replace_callback('/<em data-emoji=\"(.*?)\"><\/em>/is', "self::preg_emoji", $string);
/**
 * 输出emoji表情
 * @param $matches
 * @return mixed
 */
public static function preg_emoji($matches)
{
    $str = $matches[0];
    $str = str_replace('em:', '\u', $str);
    return $str;
}
3.直接过滤掉
/**
 * 过滤表情
 * @param $str
 * @return mixed
 */
public static function filter_emoji($str) {
    $regex = '/(\\\u[ed][0-9a-f]{3})/i';
    $str = json_encode($str);
    $str = preg_replace($regex, '', $str);
    return json_decode($str);
}


没有更多推荐了,返回首页