用Unicode表情符dynamic创buildNSString

我有string@"Hi there! \U0001F603" ,它正确地显示喜欢你喜欢的表情符号Hi there! 😃 Hi there! 😃如果我把它放在一个UILabel

但是我想像[NSString stringWithFormat:@"Hi there! \U0001F60%ld", (long)arc4random_uniform(10)]那样dynamic地创build它,但是它甚至不能编译。 如果我加倍反斜杠,它显示的Unicode值真的像Hi there! \U0001F605 Hi there! \U0001F605

我怎样才能做到这一点?

退一步说:第一个数字是1F6603 16 ,它是一个Unicode 代码点 ,为了尽可能简单,它是所有Unicode项目列表中这个表情符号的索引。 这与计算机实际处理的字节不一样,它们是“编码值”(技术上,代码单元)

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

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

(你可以在objc.io的Ole Begemann的文章中深入地读到这个东西,以及它如何与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]; 

(注意,这可能无法按预期的方式工作,不是任何代码点都是有效的。)


*请注意,对于“普通”string(例如@"b" )也是如此。

\U0001F603是在编译时评估的文字。 你想要一个可以在运行时执行的解决scheme。

所以你想有一个dynamic的Unicodestring。 %C如果Unicode字符( unichar )的格式说明符。

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

表情符号太小了。 感谢@JoshCaswell纠正我。


更新:一个工作的答案

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

  1. 创build一个function来完成所有的工作。
  2. 使用networkingsorting标准字节顺序。
  3. 没有幻数的长度。

这是我的答案

 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];