Почему я получаю разные представления NSString в UTF-8 в зависимости от конструкции строки или при работе в разных средах? - PullRequest
0 голосов
/ 13 февраля 2020

У меня есть очень простой код Objective- C, который выделяет и инициализирует NSString, а затем получает UTF-8 const char * представление этой строки следующим образом:

const char *s = [[[NSString alloc] initWithFormat:@"%s", "£"] UTF8String];

I тогда распечатать шестнадцатеричные значения единиц кода, которые составляют эту строку, используя этот код:

while(*s)
    printf("%02x ", (unsigned int) *s++);

, и я получаю следующий вывод:

ffffffc2 ffffffac ffffffc2 ffffffa3 

Это неожиданно, так как я бы предположим, что я просто получу ffffffc2 ffffffa3, поскольку символ £ состоит из двух единиц кода, представленных в шестнадцатеричном виде как c2, за которым следует a3, как вы можете см. здесь .

Вот снимок экрана этого вывода в простейшем iOS приложении, которое можно запустить локально на моем ноутбуке:

Xcode window showing hex output of UTF8 string

Обратите внимание, что вывод такой же, если я создаю NSString следующим образом:

[[NSString alloc] initWithFormat:@"%s", "\xc2\xa3"]

Если вместо этого я использую NSString в качестве аргумента для интерполяции в строку формата, то я получаю ожидаемый результат ffffffc2 ffffffa3:

[[NSString alloc] initWithFormat:@"%@", @"£"]

Что еще более странно для меня, это то, что точно такой же терпит неудачу Код , как у меня выше (первая версия), кажется, работает так, как я ожидал, когда обнаружил на онлайн-сайте Objective C codepen-type, который вы можете см. Здесь .

Почему дополнительные единицы кода добавляются в представление строки в UTF-8, когда я использую версию кода initWithFormat:@"%s", и, по-видимому, только когда я запускаю ее на своем компьютере?

1 Ответ

3 голосов
/ 14 февраля 2020

Язык C не определяет кодировку строк, скорее, он определяет набор символов, которые должны быть включены в исходный набор символов и каждый символ является байтом.

При компиляции (Objective -) C компилятор Apple Clang выглядит следующим образом, кодировка символов в строке C основана на кодировке исходного файла. По умолчанию для исходных файлов используется кодировка UTF-8, поэтому строковый литерал C "£" сохраняется в виде байтов c2, a3, 00, представляющих собой кодировку UTF-8 для «£» и ноль. byte.

Как заметил @Wileke, строковый формат %s интерпретирует свой аргумент в соответствии с кодировкой системы по умолчанию ( документация ). Эта кодировка по умолчанию выглядит как MacOSRoman, в этой кодировке байт c2 является символом «¬», а байт a3 является символом «£», и поэтому строка, которую вы производите из stringWithFormat:, содержит эти два символа в it.

Как вы уже предлагали в своих комментариях, вы можете решить свою проблему, используя initWithUTF8String:, который будет работать при условии кодировка исходного файла UTF- 8. Если ваш исходный файл использует другую кодировку, вы должны вместо этого использовать initWithCString:encoding: и указать кодировку вашего исходного файла.

Если вы не уверены в своей кодировке исходного файла, выберите файл в Xcode и посмотрите на панель проверки, там вы можете увидеть и изменить (либо переинтерпретировать, либо преобразовать существующие байты) кодировку.

Примечание : Если в вашем реальном коде строка C имеет вид не будучи сформированным из строкового литерала в том же файле, вам придется определить кодировку этой строки.

HTH

...