使用Unicode表情符号动态创建NSString

时间:2016-06-30 13:53:29

标签: ios objective-c unicode emoji

我有字符串@"Hi there! \U0001F603",如果我将其放在Hi there! 中,它会正确显示UILabel这样的表情符号。

但我想像[NSString stringWithFormat:@"Hi there! \U0001F60%ld", (long)arc4random_uniform(10)]一样动态创建它,但它甚至不编译。 如果我将反斜杠加倍,它会显示Unicode值,就像Hi there! \U0001F605

我怎样才能做到这一点?

2 个答案:

答案 0 :(得分:3)

\U0001F603是一个在编译时计算的文字。您需要一个可以在运行时执行的解决方案。

所以你想要一个带有动态unicode字符的字符串。 %C如果是unicode字符(unichar)的格式说明符。

[NSString stringWithFormat:@"Hi there! %C", (unichar)(0x01F600 + arc4random_uniform(10))];

<击>

对于表情符号来说,

unichar太小了。谢谢@JoshCaswell纠正我。

更新:工作答案

@JoshCaswell对-initWithBytes:length:encoding:有正确答案,但我想我可以写一个更好的包装器。

  1. 创建一个完成所有工作的功能。
  2. 使用network ordering作为标准字节顺序。
  3. 长度没有幻数。
  4. 这是我的回答

    NSString *MyStringFromUnicodeCharacter(uint32_t character) {
        uint32_t bytes = htonl(character); // Convert the character to a known ordering
        return [[NSString alloc] initWithBytes:&bytes length:sizeof(uint32_t) encoding:NSUTF32StringEncoding];
    }
    

    所以,在使用中......

    NSString *emoji = MyStringFromUnicodeCharacter(0x01F600 + arc4random_uniform(10));
    NSString *message = [NSString stringWithFormat:@"Hi there! %@", emoji];
    

    更新2

    最后,添加一个类别以使其成为真正的Objective-C。

    @interface NSString (MyString)
    + (instancetype)stringWithUnicodeCharacter:(uint32_t)character;
    @end
    @implementation NSString (MyString)
    + (instancetype)stringWithUnicodeCharacter:(uint32_t)character {
        uint32_t bytes = htonl(character); // Convert the character to a known ordering
        return [[NSString alloc] initWithBytes:&bytes length:sizeof(uint32_t) encoding:NSUTF32StringEncoding];
    }
    @end
    

    再一次,在使用中......

    NSString *emoji = [NSString stringWithUnicodeCharacter:0x01F600 + arc4random_uniform(10)];
    NSString *message = [NSString stringWithFormat:@"Hi there! %@", emoji];
    

答案 1 :(得分:2)

退一步,第二步:你拥有的那个号码,1F6603 16 ,是一个Unicode 代码点,试图把它简单地放在可能,是所有Unicode项列表中此表情符号的索引。这与计算机实际处理的字节不同,它们是&#34;编码的值&#34; (从技术上讲,代码单位

当您在代码中编写 literal @"\U0001F603"时,编译器会为您编写编码,编写必要的字节。*如果您在编译时没有文字时间,你必须自己做编码。也就是说,您必须将代码点转换为表示它的一组字节。例如,在NSString内部使用的UTF-16编码中,您的代码点由字节ff fe 3d d8 03 de表示。

你不能在运行时修改那个文字,最后得到正确的字节,因为编译器已经完成了它的工作并上床睡觉。

(您可以在an article by Ole Begemann at objc.io中深入了解这些内容及其与NSString的关系。)

幸运的是,其中一个可用的编码UTF-32直接表示代码点:字节的值与代码点相同。换句话说,如果将代码点编号分配给32位无符号整数,则可以获得正确的UTF-32编码数据。

这引导我们进入您需要的过程:

// Encoded start point
uint32_t base_point_UTF32 = 0x1F600;

// Generate random point
uint32_t offset = arc4random_uniform(10);
uint32_t new_point = base_point_UTF32 + offset;

// Read the four bytes into NSString, interpreted as UTF-32LE.
// Intel machines and iOS on ARM are little endian; others byte swap/change 
// encoding as necessary.
NSString * emoji = [[NSString alloc] initWithBytes:&new_point
                                            length:4
                                          encoding:NSUTF32LittleEndianStringEncoding];

(N.B。对于任意代码点,这可能无法正常工作;并非所有代码点都有效。)

*注意,它对#34;正常&#34;做同样的事情。像@"b"这样的字符串。