Как преобразовать значение 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];
Но это тоже не сработает.
Я, очевидно, делаю что-то ужасно неправильно, но я не знаю, что.
Может кто-то мне помочь, пожалуйста?
Спасибо!
Ответы
Ответ 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).