使用 Unicode 表情符号动态创建 NSString
Dynamically create NSString with Unicode emoji
我有字符串 @"Hi there! \U0001F603"
,如果我将它放在 UILabel
.
中,它会正确显示像 Hi there!
这样的表情符号
但我想像 [NSString stringWithFormat:@"Hi there! \U0001F60%ld", (long)arc4random_uniform(10)]
那样动态创建它,但它甚至无法编译。
如果我加倍反斜杠,它会像 Hi there! \U0001F605
.
这样显示 Unicode 值
我怎样才能做到这一点?
\U0001F603
是在编译时评估的文字。您想要一个可以在运行时执行的解决方案。
所以你想要一个带有动态 unicode 字符的字符串。 %C
如果 unicode 字符的格式说明符 (unichar
)。
[NSString stringWithFormat:@"Hi there! %C", (unichar)(0x01F600 + arc4random_uniform(10))];
unichar
对于表情符号来说太小了。感谢@JoshCaswell 纠正我。
更新:有效答案
@JoshCaswell 对 -initWithBytes:length:encoding:
的回答是正确的,但我想我可以写一个更好的包装器。
- 创建一个函数来完成所有工作。
- 使用 network ordering 作为标准字节顺序。
- 长度没有幻数。
这是我的答案
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];
先退后一步:您拥有的号码 1F660316 是一个 Unicode 代码点,尽量简单地说,就是这个表情符号在所有 Unicode 项目列表中的索引。这与计算机实际处理的字节不同,后者是 "encoded value"(技术上,代码 units。
当您在代码中编写 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。对于任意代码点,这可能无法按预期工作;并非所有代码点都有效。)
*注意,它对 "normal" 字符串(如 @"b"
)也做同样的事情。
我有字符串 @"Hi there! \U0001F603"
,如果我将它放在 UILabel
.
Hi there!
这样的表情符号
但我想像 [NSString stringWithFormat:@"Hi there! \U0001F60%ld", (long)arc4random_uniform(10)]
那样动态创建它,但它甚至无法编译。
如果我加倍反斜杠,它会像 Hi there! \U0001F605
.
我怎样才能做到这一点?
\U0001F603
是在编译时评估的文字。您想要一个可以在运行时执行的解决方案。
所以你想要一个带有动态 unicode 字符的字符串。 %C
如果 unicode 字符的格式说明符 (unichar
)。
[NSString stringWithFormat:@"Hi there! %C", (unichar)(0x01F600 + arc4random_uniform(10))];
unichar
对于表情符号来说太小了。感谢@JoshCaswell 纠正我。
更新:有效答案
@JoshCaswell 对 -initWithBytes:length:encoding:
的回答是正确的,但我想我可以写一个更好的包装器。
- 创建一个函数来完成所有工作。
- 使用 network ordering 作为标准字节顺序。
- 长度没有幻数。
这是我的答案
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];
先退后一步:您拥有的号码 1F660316 是一个 Unicode 代码点,尽量简单地说,就是这个表情符号在所有 Unicode 项目列表中的索引。这与计算机实际处理的字节不同,后者是 "encoded value"(技术上,代码 units。
当您在代码中编写 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。对于任意代码点,这可能无法按预期工作;并非所有代码点都有效。)
*注意,它对 "normal" 字符串(如 @"b"
)也做同样的事情。