Подтвердить что ты не робот

Как преобразовать значение unichar в NSString в Objective-C?

У меня есть международный символ, хранящийся в unichar-переменной. Этот символ не исходит из файла или URL-адреса. Сама переменная хранит только unsigned short (0xce91), который находится в формате UTF-8 и переводится в прописную букву "A". Я пытаюсь превратить этот символ в переменную NSString, но я терплю неудачу.

Я пробовал два разных способа, обе неудачные:

unichar greekAlpha = 0xce91; //could have written greekAlpha = 'Α' instead.

NSString *theString = [NSString stringWithFormat:@"Greek Alpha: %C", greekAlpha];

Нехорошо. Я получаю странные китайские персонажи. В качестве опоры это отлично работает с английскими символами.

Затем я также пробовал это:

NSString *byteString = [[NSString alloc] initWithBytes:&greekAlpha
                                                length:sizeof(unichar)
                                              encoding:NSUTF8StringEncoding];

Но это тоже не сработает. Я, очевидно, делаю что-то ужасно неправильно, но я не знаю, что. Может кто-то мне помочь, пожалуйста? Спасибо!

4b9b3361

Ответ 1

Так как 0xce91 находится в формате UTF-8, а %C ожидает, что он будет в UTF-16, простое решение, подобное выше, не будет работать. Для работы stringWithFormat:@"%C" вам нужно ввести 0x391, который является Unicode UTF-16.

Чтобы создать строку из Unichar с кодировкой UTF-8, вам нужно сначала разделить юникод на это октеты, а затем использовать initWithBytes:length:encoding.

unichar utf8char = 0xce91; 
char chars[2];
int len = 1;

if (utf8char > 127) {
    chars[0] = (utf8char >> 8) & (1 << 8) - 1;
    chars[1] = utf8char & (1 << 8) - 1; 
    len = 2;
} else {
    chars[0] = utf8char;
}

NSString *string = [[NSString alloc] initWithBytes:chars
                                            length:len 
                                          encoding:NSUTF8StringEncoding];

Ответ 2

unichar greekAlpha = 0x0391;
NSString* s = [NSString stringWithCharacters:&greekAlpha length:1];

И теперь вы можете включить этот NSString в другой так, как вам нравится. Обратите внимание, однако, что теперь законно вводить греческую альфа непосредственно в литерал NSString.

Ответ 3

Вышеприведенный ответ велик, но не учитывает символы UTF-8 длиной более 16 бит, например. символ многоточия - 0xE2,0x80,0xA6. Вот настройка кода:

if (utf8char > 65535) {
   chars[0] = (utf8char >> 16) & 255;
   chars[1] = (utf8char >> 8) & 255;
   chars[2] = utf8char & 255; 
   chars[3] = 0x00;
} else if (utf8char > 127) {
    chars[0] = (utf8char >> 8) & 255;
    chars[1] = utf8char & 255; 
    chars[2] = 0x00;
} else {
    chars[0] = utf8char;
    chars[1] = 0x00;
}
NSString *string = [[[NSString alloc] initWithUTF8String:chars] autorelease];

Обратите внимание на другой метод инициализации строки, который не требует параметра длины.

Ответ 4

Вот алгоритм кодирования UTF-8 для одного символа:

if (utf8char<0x80){ 
    chars[0] = (utf8char>>0)  & (0x7F | 0x00);
    chars[1] = 0x00;
    chars[2] = 0x00;
    chars[3] = 0x00;
}
else if (utf8char<0x0800){
    chars[0] = (utf8char>>6)  & (0x1F | 0xC0);
    chars[1] = (utf8char>>0)  & (0x3F | 0x80);
    chars[2] = 0x00;
    chars[3] = 0x00;
}
else if (utf8char<0x010000) {
    chars[0] = (utf8char>>12) & (0x0F | 0xE0);
    chars[1] = (utf8char>>6)  & (0x3F | 0x80);
    chars[2] = (utf8char>>0)  & (0x3F | 0x80);
    chars[3] = 0x00;
}
else if (utf8char<0x110000) {
    chars[0] = (utf8char>>18) & (0x07 | 0xF0);
    chars[1] = (utf8char>>12) & (0x3F | 0x80);
    chars[2] = (utf8char>>6)  & (0x3F | 0x80);
    chars[3] = (utf8char>>0)  & (0x3F | 0x80);
}

Ответ 5

Приведенный выше код является моральным эквивалентом unichar foo = 'abc';.

Проблема заключается в том, что 'Α' не сопоставляется одному байту в "наборе символов выполнения" (я предполагаю UTF-8), который является "определяемым реализацией" в C99 §6.4.4.4 10:

Значение целочисленной символьной константы, содержащей более одного символа (например, 'ab'), или содержащее символ или escape-последовательность, которая не отображается на однобайтовый символ выполнения, определяется реализацией.

Один из способов - сделать 'ab' равным 'a'<<8|b. Некоторые заголовки систем Mac/iOS полагаются на это для таких вещей, как OSType/FourCharCode/FourCC; единственный в iOS, который приходит на ум, - это пиксельные форматы CoreVideo. Это, однако, невозможно.

Если вам действительно нужен литерал unichar, вы можете попробовать L'A' (технически это литерал wchar_t, но для OS X и iOS wchar_t обычно является UTF-16, поэтому он будет работать на вещи внутри BMP). Однако гораздо проще использовать @"Α" (который работает до тех пор, пока вы правильно установите кодировку исходного кода) или @"\u0391" (который работал с по крайней мере с iOS 3 SDK).