我们都知道 用户使用移动设备发表评论或昵称时会输入一些emoji表情,服务器对emoji表情直接保存不兼容, 如果客户端直接把表情符号传给服务端保存的话, 会得到一个保存失败的错误, 一般原因是数据库使用的是mysql utf8字符集存储的。utf8最大支持3个字节的unicode,而emoji表情和一些特殊符号需要4个字节才能存储。因此导致用户输入的emoji表情时存储失败。 那如何解决这个问题呢,下面列出几种解决的办法:
办法一:
- 修改数据库字符集编码,通过把原来的utf8编码修改为utf8mb4可以完美解决问题,操作步骤如下:
修改mysql服务器配置文件中的 character_set_database=utf8mb4 和 character_set_server=utf8mb4,可以是mysql支持utf8mb4编码。
在应用中连接mysql服务器时指定字符集为utf8mb4可以 保证读取和写入的数据是utf8mb4的编码,从而达到客户端和服务器端一直。在连接时指定字符集将影响到 character_set_client 和character_set_connection 两个参数为utf8mb4。
-
修改现有的数据库表字符集,如下
修改为
- 然后修改表中字段的字符集为utf8mb4,不推荐在一张表中使用多种字符集。
utf8mb4的优势
1、utf8mb4是今后的趋势
2、utf8mb4是utf8的超集,兼容utf8并且可以支持emoji表情存储
utf8mb4的缺点
由于utf8mb4采用4个字节存储数据,而utf8最多使用3个字节存储数据,所以使用utf8mb4需要占用更大的存储空间
风险点
1、在一张表里面混用utf8字符集和utf8mb4字符集在进行 连接 查询时会发生类型的隐式转换,导致索引失效
规避风险
1、在同一个表中使用相同的字符集编码,禁止混用不同字符集
2、先在测试环境实施改造,观察运行情况
3、做好数据的备份工作
效果演示
办法二:
- 在客户端输入表情的时候直接过滤掉那些表情,只要不过滤掉不传给服务器, 就不会存在保存失败的情况; 当然这个办法没有从根本上解决保存的问题, 如果你的需求需要保存表情, 自然这个方法不满足要求;
注意:保持严格遵守不触碰用户数据的原则,如果能尽量考虑用户体验的前提下,该方案慎重考虑
- 这里是边输入边用正则表达式去过滤表情, 可以在输入文字的代理方法里面加做过滤的逻辑;
#pragma mark - <UITextViewDelegate>
- (void)textViewDidChange:(UITextView *)textView
{
NSLog(@"没有过滤前输入的字符串===%@",textView.text);
NSString *filterString = [self disableEmoji:textView.text];
NSLog(@"过滤Emoji表情后的字符串===%@",filterString);
textView.text = filterString;
}
/**
* 正则过滤表情
*/
- (NSString *)disableEmoji:(NSString *)text
{
if (!text.length) return text;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[^\\u0020-\\u007E\\u00A0-\\u00BE\\u2E80-\\uA4CF\\uF900-\\uFAFF\\uFE30-\\uFE4F\\uFF00-\\uFFEF\\u0080-\\u009F\\u2000-\\u201f\r\n]" options:NSRegularExpressionCaseInsensitive error:nil];
NSString *modifiedString = [regex stringByReplacingMatchesInString:text
options:0
range:NSMakeRange(0, [text length])
withTemplate:@""];
return modifiedString;
}
办法三:
- 第三种办法使用base64编码解决,此可以联想到我们在请求有中文链接的网址时会请求失败, 正常的处理是先把含有中文的网址进行编码后在请求就会成功, 因此,我们保存表情时也可以你用这种办法;
使用:这里在你把转码后的操作发给服务器后, 需要做的一个额外操作就是, 你再从服务器取回来显示时, 需要反转一下之前的编码才能正常显示出表情符号, 否则就是一堆乱码, 如: 123456%F0%9F%98%83%E2%98%BA%F0%9F%98%9A%F0%9F%98%99%F0%9F%99%8412
;
- 把含有表情的字符串进行编码后再发送给服务端:
NSString *inputText = [self.editTextView.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
- 注意: 这里如果你输入的字符串中已经含有一些已转义的特殊符号: % @ $等时, 上面的方法就不会再对这些特殊的进行转码, 可以使用下面的方法
NSString *encodedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)urlString, (CFStringRef)@"!$&'()*+,-./:;=?@_~%#[]", NULL, kCFStringEncodingUTF8);
- 对从服务器获取回来含有表情的字符串进行反转后显示在页面上:
NSString *showText = [serverString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
- 把编码的字符串反转之后的显示效果图:
注意点:
1、如果是针对一些用户输入的评论内容,可能需要进行人工审核,需要看到原始的数据,编码后会无法清晰的查看问题;
2、管理后台需要对评论内容,用户昵称等内容进行模糊匹配,编码后无法实现搜索;
3、评论内容从接收到最终在站点显示需要经过多个流程,频繁编码及解码会损失一些性能;
办法四:
- 第三种办法就是把输入的表情转成
NSData
的二进制数据传给服务器;
NSData *data =[inputText dataUsingEncoding:NSUTF8StringEncoding];
不过这种办法客户端和服务端两边处理都比较麻烦, 不建议使用这种方法;