【问题标题】:MySQL, UTF-8 and Emoji charactersMySQL、UTF-8 和表情符号字符
【发布时间】:2014-08-06 21:15:31
【问题描述】:

我正在开发一个带有 PHP+MySQL 后端的 iOS 应用程序。该应用程序有一个聊天部分,需要支持表情符号。 我的表是 utf8_unicode_ci。如果我不在我的脚本中调用“set names utf8”,表情符号实际上可以工作 - 无论在数据库中输入什么,都会按应有的方式返回给客户端。

问题是这个(如果我理解正确的话)在数据库中错误地存储了特殊字符,这会破坏字符串比较(即比较字符串时 ï 不再与 i 相同)。

但是,如果我调用 set names utf8,突然表情符号字符被插入为一堆问号。

对处理这个问题的正确方法有什么建议吗?谢谢!

【问题讨论】:

    标签: php mysql ios utf-8 emoji


    【解决方案1】:

    问题是数据库是否有变音不敏感比较。另一个问题是组合字符,ï 可以表示为一个 unicode 字符或两个形成代理对。有一些方法可以将字符串转换为预先组合或分解的形式:precomposedStringWith* 和 decomposedStringWith*。

    似乎 MySQL 支持两种形式的 unicode ucs2(这是一种被 utf16 取代的旧形式),每个字符 16 位,utf8 每个字符最多 3 个字节。坏消息是这两种形式都不支持需要 17 位的平面 1 字符。 (主要是表情符号)。看起来 MySQL 5.5.3 及更高版本还支持 utf8mb4、utf16 和 utf32 支持 BMP 和补充字符(阅读表情符号)。见MySQL Unicode Character Sets

    这里有一些代码和结果来演示不同的 unicode 字节表示。
    Unicode 是 21 位编码系统。
    UTF32 直接表示代码点,清楚地展示了分解的代理对。
    UTF8 和 UTF16 需要一个或多个字节来表示一个 unicode 字符。

    NSLog(@"character: %@", @"Å");
    NSLog(@"decomposedStringWithCanonicalMapping UTF8:  %@", [[@"Å" decomposedStringWithCanonicalMapping] dataUsingEncoding:NSUTF8StringEncoding]);
    NSLog(@"decomposedStringWithCanonicalMapping UTF16: %@", [[@"Å" decomposedStringWithCanonicalMapping] dataUsingEncoding:NSUTF16BigEndianStringEncoding]);
    NSLog(@"decomposedStringWithCanonicalMapping UTF32: %@", [[@"Å" decomposedStringWithCanonicalMapping] dataUsingEncoding:NSUTF32BigEndianStringEncoding]);
    
    NSLog(@"precomposedStringWithCanonicalMapping UTF8:  %@", [[@"Å" precomposedStringWithCanonicalMapping] dataUsingEncoding:NSUTF8StringEncoding]);
    NSLog(@"precomposedStringWithCanonicalMapping UTF16: %@", [[@"Å" precomposedStringWithCanonicalMapping] dataUsingEncoding:NSUTF16BigEndianStringEncoding]);
    NSLog(@"precomposedStringWithCanonicalMapping UTF32: %@", [[@"Å" precomposedStringWithCanonicalMapping] dataUsingEncoding:NSUTF32BigEndianStringEncoding]);
    
    NSLog(@"character: %@", @"?");
    NSLog(@"dataUsingEncoding UTF8:  %@", [@"?" dataUsingEncoding:NSUTF8StringEncoding]);
    NSLog(@"dataUsingEncoding UTF16: %@", [@"?" dataUsingEncoding:NSUTF16BigEndianStringEncoding]);
    NSLog(@"dataUsingEncoding UTF32: %@", [@"?" dataUsingEncoding:NSUTF32BigEndianStringEncoding]);
    

    // 对于某些代理对没有其他形式

    NSString *aReverse = [[NSString alloc] initWithBytes:"\xD8\x3C\xDD\x70\x00" length:4 encoding:NSUTF16BigEndianStringEncoding];
    NSLog(@"character: %@", aReverse);
    NSLog(@"dataUsingEncoding UTF8:  %@", [aReverse dataUsingEncoding:NSUTF8StringEncoding]);
    NSLog(@"dataUsingEncoding UTF16: %@", [aReverse dataUsingEncoding:NSUTF16BigEndianStringEncoding]);
    NSLog(@"dataUsingEncoding UTF32: %@", [aReverse dataUsingEncoding:NSUTF32BigEndianStringEncoding]);
    

    NSLog 输出:

    character: Å
    decomposedStringWithCanonicalMapping UTF8:  <41cc8a>   
    decomposedStringWithCanonicalMapping UTF16: <0041030a>   
    decomposedStringWithCanonicalMapping UTF32: <00000041 0000030a>   
    
    precomposedStringWithCanonicalMapping UTF8:  <c385>   
    precomposedStringWithCanonicalMapping UTF16: <00c5>   
    precomposedStringWithCanonicalMapping UTF32: <000000c5>   
    
    character: ?
    dataUsingEncoding UTF8:  <f09f98b1>   
    dataUsingEncoding UTF16: <d83dde31>   
    dataUsingEncoding UTF32: <0001f631>   
    
    character: ?
    dataUsingEncoding UTF8:  <f09f85b0>
    dataUsingEncoding UTF16: <d83cdd70>
    dataUsingEncoding UTF32: <0001f170>
    

    【讨论】:

    • 这似乎是非常有用的信息。我目前无法验证,因为我目前无法升级我的 MySQL,但我会假设您是正确的并接受您的回答 :) 谢谢!
    • 如果您不介意,我还有一个问题。如果我不需要像我描述的那样进行字符串匹配,那么不调用集合名称 utf8 还有其他缺点吗?我知道数据插入不正确,但是在客户端显示数据时它可以工作。
    • 不幸的是,我对set names utf8 一无所知,我已经有好几年没有编写与 MySQL 一起工作的代码了。请使用平面 1 代码点进行测试(表情符号在平面 1 中)。也是代理对,但它们可能只是比较的问题。我在答案中添加了一些代码和结果,以演示不同的 unicode 字节表示。
    • 想通知您,我升级了 MySQL 并将我的字符集更改为 utf8mb4_unicode_ci - 现在一切都很好。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-26
    • 2013-07-07
    • 2011-12-10
    • 2020-09-19
    • 2016-06-10
    • 1970-01-01
    相关资源
    最近更新 更多