Преобразование строки NSString в и из UTF32 - PullRequest
4 голосов
/ 23 июня 2011

Я работаю с базой данных, которая включает шестнадцатеричные коды для символов UTF32.Я хотел бы взять эти символы и сохранить их в строке NSString.Мне нужно иметь подпрограммы для преобразования в обоих направлениях.

Чтобы преобразовать первый символ строки NSString в значение Unicode, эта подпрограмма, кажется, работает:

const unsigned char *cs = (const unsigned char *)
    [s cStringUsingEncoding:NSUTF32StringEncoding];
uint32_t code = 0;
for ( int i = 3 ; i >= 0 ; i-- ) {
    code <<= 8;
    code += cs[i];
}
return code;

Однако я не могусделать обратное (то есть взять один код и преобразовать его в строку NSString).Я подумал, что могу просто сделать обратное тому, что я делаю выше, просто создав C-строку с символом UTF32 в ней с байтами в правильном порядке, а затем создать NSString из этого с использованием правильной кодировки.

Однако преобразование в / из cstrings не кажется мне обратимым.

Например, я пробовал этот код, и строка "tmp" не равна исходной строке "s".

char *cs = [s cStringUsingEncoding:NSUTF32StringEncoding];
NSString *tmp = [NSString stringWithCString:cs encoding:NSUTF32StringEncoding];

Кто-нибудь знает, что я делаю не так?Должен ли я использовать "wchar_t" для cstring вместо char *?

Любая помощь очень ценится!

Спасибо, Рон

Ответы [ 2 ]

14 голосов
/ 23 июня 2011

У вас есть несколько разумных вариантов.

1. Конверсия

Первый - преобразовать ваш UTF32 в UTF16 и использовать их с NSString, поскольку UTF16 - это «родная» кодировка NSString. Это не так уж сложно. Если символ UTF32 находится в BMP (например, старшие два байта равны 0), вы можете просто привести его к unichar напрямую. Если он находится в любой другой плоскости, вы можете преобразовать его в суррогатную пару символов UTF16. Вы можете найти правила на странице Википедии . Но быстрое (не проверенное) преобразование будет выглядеть как

UTF32Char inputChar = // my UTF-32 character
inputChar -= 0x10000;
unichar highSurrogate = inputChar >> 10; // leave the top 10 bits
highSurrogate += 0xD800;
unichar lowSurrogate = inputChar & 0x3FF; // leave the low 10 bits
lowSurrogate += 0xDC00;

Теперь вы можете создать строку NSString, используя оба символа одновременно:

NSString *str = [NSString stringWithCharacters:(unichar[]){highSurrogate, lowSurrogate} length:2];

Чтобы вернуться назад, вы можете использовать [NSString getCharacters:range:], чтобы получить обратно unichar, а затем обратить вспять алгоритм суррогатной пары, чтобы вернуть ваш символ UTF32 (любые символы, которые не находятся в диапазоне 0xD800-0xDFFF, должны быть просто приведены к UTF32 непосредственно).

2. Байт-буферы

Другой вариант - позволить NSString выполнять преобразование напрямую, без использования cStrings. Чтобы преобразовать значение UTF32 в строку NSString, вы можете использовать что-то вроде следующего:

UTF32Char inputChar = // input UTF32 value
inputChar = NSSwapHostIntToLittle(inputChar); // swap to little-endian if necessary
NSString *str = [[[NSString alloc] initWithBytes:&inputChar length:4 encoding:NSUTF32LittleEndianStringEncoding] autorelease];

Чтобы вернуть его снова, вы можете использовать

UTF32Char outputChar;
if ([str getBytes:&outputChar maxLength:4 usedLength:NULL encoding:NSUTF32LittleEndianStringEncoding options:0 range:NSMakeRange(0, 1) remainingRange:NULL]) {
    outputChar = NSSwapLittleIntToHost(outputChar); // swap back to host endian
    // outputChar now has the first UTF32 character
}
1 голос
/ 28 апреля 2018

Здесь есть две проблемы:

1

Во-первых, [NSString cStringUsingEncoding:] и [NSString getCString:maxLength:encoding:] возвращают C-строку с собственным порядком байтов (немного) без добавления спецификации при использовании NSUTF32StringEncoding и NSUTF16StringEncoding.

Стандарт Unicode гласит, что : (см. «Как мне следует обращаться с спецификациями»)

"If there is no BOM, the text should be interpreted as big-endian."

Это также указано в документации NSString : (см. "Интерпретация данных в кодировке UTF-16")

"... if the byte order is not otherwise specified, NSString assumes that the UTF-16 characters are big-endian, unless there is a BOM (byte-order mark), in which case the BOM dictates the byte order."

Хотя они относятся к UTF-16, то же самое относится и к UTF-32.

2

Вторым является то, что [NSString stringWithCString:encoding:] внутренне использует CFStringCreateWithCString для создания C-строки. Проблема в том, что CFStringCreateWithCString принимает строки только с использованием 8-битных кодировок . Из документации : (см. Раздел «Параметры»)

The string must use an 8-bit encoding.

Чтобы решить эту проблему:

  1. Явно укажите порядок кодирования, который вы хотите использовать обоими способами (NSString -> C-string и C-string -> NSString)
  2. Используйте [NSString initWithBytes:length:encoding:] при попытке создать строку NSSt из строки C, закодированной в UTF-32 или UTF-16.

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...