Выполните String.Encoding.utf16 и String.Encoding. utf16BigEndian означает то же самое, то есть UTF16BigEndian?

У меня есть байты для строки, закодированной с помощью utf16 big endian. Эти байты читаются мной из файла, которым поделился со мной мой коллега, который подтверждает, что строка является бигендианской utf16.

В демонстрационных целях я прочитал файл, чтобы интерпретировать строку. Код выглядит следующим образом:

let bundle = Bundle(for: ViewController.self)
guard let url = bundle.url(forResource: "TestBingEndian", withExtension: "txt") else { return }
let data = try! Data(contentsOf: url)
        print(data)

let bigEndianString = String(bytes: data, encoding: .utf16BigEndian)
print("bigEndianString: \(bigEndianString!)")

let littleEndian = String(bytes: data, encoding: .utf16LittleEndian)
print("littleEndian: \(littleEndian!)")

let endiannessNotSpecifiedString = String(bytes: data, encoding: .utf16)
print("endiannessNotSpecifiedString: \(endiannessNotSpecifiedString!)")

Вывод для bigEndianString такой, как и ожидалось.

Вывод для littleEndian был бесполезен, так как в моем случае это был мусор.

Результат для endiannessNotSpecifiedString также оказался ожидаемым и совпал с bigEndianString.

Итак, мой вопрос: являются ли .utf16 и .utf16BigEndian одним и тем же?

PS: Моя машина с прямым порядком байтов. Я думал, что .utf16 должен быть тем, чем являются мои машины. Но, согласно моим тестам, это бигендиан.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
474
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Итак, мой вопрос: являются ли .utf16 и .utf16BigEndian одним и тем же?

Нет. Правильный код UTF-16 должен содержать спецификацию в начале файла.

let str = "Hello, World!"

let dataUTF16 = str.data(using: .utf16)!
print(dataUTF16 as NSData)

let dataUTF16BE = str.data(using: .utf16BigEndian)!
print(dataUTF16BE as NSData)

let dataUTF16LE = str.data(using: .utf16LittleEndian)!
print(dataUTF16LE as NSData)

Выход:

<fffe4800 65006c00 6c006f00 2c002000 57006f00 72006c00 64002100>
<00480065 006c006c 006f002c 00200057 006f0072 006c0064 0021>
<48006500 6c006c00 6f002c00 20005700 6f007200 6c006400 2100>

0xff, 0xfe представляет спецификацию с прямым порядком байтов. В обратном порядке это будет 0xfe, 0xff.

С помощью .utf16 вы можете читать правильные данные UTF-16 (я имею в виду правильную спецификацию) даже на платформе с несовпадением байтов.

Поставьте print(data as NSData) и проверьте первые два байта вашего data. Я предполагаю, что он содержит 0xfe, 0xff (BOM в обратном порядке.)


Кажется, мое предположение было неверным, и .utf16 в Apple Foundation предпочитает обратный порядок байтов, а не родной порядок байтов платформы, когда спецификация не найдена. (Возможно, есть какая-то историческая причина, поскольку Apple использовала платформы Big Endian, 68k или Power-PC.A с комментарием Мартина Р., он определен в стандарте Unicode. Кажется, мне нужно освежить свои знания.)

Но вам лучше указать .utf16BigEndian, когда вы знаете, что ваши данные не содержат спецификацию и в Big Endian, .utf16 для данных, содержащих правильную спецификацию.

let str = "Hello, World!"

let dataUTF16 = str.data(using: .utf16)!
print(dataUTF16 as NSData)

let strUTF16asUTF16 = String(data: dataUTF16, encoding: .utf16)
debugPrint(strUTF16asUTF16) //->Optional("Hello, World!")
let strUTF16asUTF16BE = String(data: dataUTF16, encoding: .utf16BigEndian)
debugPrint(strUTF16asUTF16BE) //->Optional("䠀攀氀氀漀Ⰰ 圀漀爀氀搀℀")
let strUTF16asUTF16LE = String(data: dataUTF16, encoding: .utf16LittleEndian)
debugPrint(strUTF16asUTF16LE) //->Optional("Hello, World!")

Когда почти все символы состоят из символов ASCII, некоторое предсказание порядка байтов сработает, но когда большинство из них состоит из символов, отличных от ASCII, такие предсказания могут быть неверными. Это применимо, если вы прогнозируете порядок байтов.

Но в целом вы должны использовать стандарт Unicode, в котором говорится, что если нет спецификации, которую нужно найти, вы должны рассматривать байты как big endian.

Вы сгенерировали байты из строки программно. Я распечатал свои байты как NSData, как вы сказали, а 0xfe, 0xff отсутствуют. Спецификация отсутствует в байтах, которые я читал из файла. Итак, как в этом случае решается порядок следования байтов?

Rohan Bhale 08.04.2019 08:42

Мой вывод: <00480061 00720065 00730068 00200050 00690073 0065> Здесь явно отсутствует спецификация.

Rohan Bhale 08.04.2019 08:47

@RohanBhale, спасибо за уточнение, мое предположение было неверным, но я могу показать вам пример того, что .utf16 и utf16BigEndian работают по-разному.

OOPer 08.04.2019 08:53

Ты прав. Я дополнительно прочитал здесь en.wikipedia.org/wiki/Byte_order_mark.

Rohan Bhale 08.04.2019 08:58

Если спецификации нет, то можно определить, является ли текст UTF-16, и его порядок байтов путем поиска символов ASCII (т. е. 0 байт, примыкающий к байту в диапазоне 0x20-0x7E, а также 0x0A и 0x0D для CR и ЛФ). Большое число (т. е. гораздо большее, чем случайное совпадение) в одном и том же порядке является очень хорошим признаком UTF-16, и то, находится ли 0 в четных или нечетных байтах, указывает порядок байтов. Однако это может привести как к ложноположительным, так и к ложноотрицательным результатам. В целом есть вероятность, что в некоторых случаях .utf16 может дать сбой. Они предсказывают это, используя шаблоны, и предсказания могут не сработать.

Rohan Bhale 08.04.2019 08:59

Спасибо за подробный комментарий. На самом деле, я не знал, что Apple .utf16 использует Big Endian по умолчанию (не угадывая порядок следования байтов, не используя порядок байтов платформы). Кажется, теперь вы очень хорошо знаете, какую кодировку следует использовать для ваших данных.

OOPer 08.04.2019 09:16

По-видимому, это по-прежнему применяется к строкам Swift: «При создании объекта NSString из строки в кодировке UTF-16 (или потока байтов, интерпретируемого как UTF-16), если порядок байтов не указан иначе, NSString предполагает, что символы UTF-16 имеют обратный порядок байтов,, если нет BOM (знак порядка байтов), и в этом случае BOM диктует порядок байтов».

Martin R 08.04.2019 09:16

@MartinR Интересно, поэтому Apple не предсказывает (вики предполагает, что в таком случае должно быть предсказание). Предполагается, что это прямой порядок байтов.

Rohan Bhale 08.04.2019 09:28

@RohanBhale: В этой статье Wiki также цитируется стандарт Unicode: «Схема кодирования UTF-16 может начинаться со спецификации, а может и не начинаться. Однако при отсутствии спецификации и протокола более высокого уровня порядок байтов в схеме кодирования UTF-16 является обратным порядком байтов».

Martin R 08.04.2019 09:30

@MartinR Спасибо. Это также проясняет мои основные сомнения, почему из-за этого не происходит сбоев приложений. Таким образом, существует четкий стандарт для использования BigEndian в случае отсутствия спецификации.

Rohan Bhale 08.04.2019 09:34

Другие вопросы по теме