2

我想将一堆表情符号图标添加到数组中。从我之前的问题中,我发现了如何在NSString. 现在我想制作一个循环并将这些图标添加到一个数组中。这应该相当容易,因为 unicode 在特定范围内,因此应该执行以下操作:

for (int i = 0; i < 10; i++)
    [someArray addObject:[NSString stringWithFormat:@"\U0001F43%i", i]];

问题是,这样做时我收到一条错误消息:

不完整的通用字符名称。

有谁知道这样做的方法?

4

3 回答 3

4

这是因为转义序列\Uxxxxxxxx 由编译器评估,编译器将其替换为相应的 Unicode 代码点。然后 when 方法stringWithFormat:将格式说明符替换%ii. 最后的字符串是对应\Uxxxxxxxx的字符和表示的字符的串联istringWithFormat:用其他字符替换字符;它不会改变现有的字符。

但问题是,这里编译器看到一个不完整的转义序列,因为你只写了 7 个十六进制数字。所以它无法生成字符串并引发错误。

解决方案是在运行时生成字符(一个简单的整数值)并使用它创建一个字符串+[NSString stringWithCharacters:length]

但是,如果您查看标头,您会看到NSString将其字符存储unichar为定义为unsigned short,即 16 位长的值,而 Unicode 代码点U+1F430() 至少需要 17 位。

因此,您不能使用单个unichar字符来表示该代码点。不过不用担心:您可以使用两个字符来表示它。

你迷路了?这里解释!Unicode 没有定义字符,它定义了代码点,它们是范围内的任意整数值U+0000U+10FFFF。然后,实现决定如何使用字符来表示这些代码点。只要它设法表示所有有效的代码点,实现就可以使用它想要的任何数据类型作为字符。最简单的解决方案是使用 32 位长的整数,但这需要太多内存,因为您使用的大多数代码点都在第一个 Unicode 计划 ( U+0000- U+FFFF) 中。因此,使用 16 位长字符的UTF-16 编码NSString存储代码点。

在 UTF-16 中,超出U+FFFF的每个代码点都使用范围内的一对字符(称为代理对)存储0xD800- 0xDFFF(相应的代码点在 Unicode 标准中明确保留)。

总之,任何有效的 Unicode 代码点都可以用一个或两个unichar字符来表示。那里描述了这样做的方法。这是一个简单的实现:

static NSString *stringWithCodePoint(uint32_t codePoint)
{
    // NOTE: As I edited the answer, you'll find a simpler implementation of
    // this function below

    unichar characters[2];
    NSUInteger length;

    if ( codePoint <= 0xD7FF || (codePoint >= 0xE000 && codePoint <= 0xFFFF) ) {
        characters[0] = codePoint;
        length = 1;
    }
    if ( codePoint >= 0x10000 && codePoint <= 0x10ffff ) {
        codePoint -= 0x10000;
        characters[0] = 0xD800 + (codePoint >> 10);
        characters[1] = 0xDC00 + (codePoint & 0x3ff);
        length = 2;
    }
    else {
        length = 0; // invalid code point
    }

    return [NSString stringWithCharacters:characters length:length];
}

现在我们可以从任何有效的代码点生成一个字符串,我们只需要更新代码以使用我们之前编写的函数:

for (int i = 0; i < 10; i++)
    [someArray addObject:stringWithCodePoint(0x0001F430 + i)];

编辑:我只是想出了一种更简单的方法来NSString从代码点获取 a 。它通过使用-[NSString initWithBytes:length:encoding:]NSUTF32StringEncoding编码工作:

static NSString *stringWithCodePoint(uint32_t codePoint)
{
    NSString *string = [[NSString alloc] initWithBytes:&codePoint length:4 encoding:NSUTF32StringEncoding];
    // You may remove the next 3 lines if you use ARC
#if ! __has_feature(objc_arc)
    [string autorelease];
#endif
    return string;
}
于 2012-06-26T19:47:48.133 回答
0

使用%C代替%i

所以:

[someArray addObject:[NSString stringWithFormat:@"\U0001F43%C", i]];
于 2012-06-26T19:04:25.783 回答
0

注意这个类似的问题。正如其答案之一所解释的那样,字符串文字中的反斜杠转义是在 compile time评估的。如果您想使用\Uxxxx转义来制作 Unicode 字符,则xxxxall 必须是字符串文字中的数字。

根据另一个答案,您可以做的是使用格式说明符%C- 不与\Uxxxx转义符一起使用,而是单独使用 - 并将完整的字符代码作为整数传递。(实际上, a wchar_t,它现在是 Mac OS X 上的 32 位整数,您需要它,因为您要查找的字符代码超过 16 位长。)要将它与基数放在一起,您可以只需添加整数:

wchar_t base = 0x0001F430; // unfamiliar? we start with 0x for hexadecimal integers
for (int i = 0; i < 10; i++)
    [someArray addObject:[NSString stringWithFormat:@"%C", base + i]];

There's also stringWithCharacters: but that explicitly takes a (16-bit) unichar, so you'd need to use a character sequence to encode your emoji in UTF-16.

于 2012-06-26T19:48:50.093 回答