Сделайте String.Encoding.utf16 и String.Encoding.utf16BigEndian означает то же самое, то есть UTF16BigEndian? - PullRequest
1 голос
/ 08 апреля 2019

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

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

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 должен быть тем, что есть в моих машинах.Но, согласно моим тестам, он оказывается бигендистским.

1 Ответ

1 голос
/ 08 апреля 2019

Итак, мой вопрос: .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 (спецификация в старшем порядке).


Кажется, мое предположение было неверным, и .utf16 в Apple Foundation предпочитает Big Endian, а не собственный порядковый номер платформы, когда спецификация не найдена. ( Возможно, есть какая-то историческая причина, так как Apple использовала платформы Big Endian, 68k или Power-PC. Как и в комментарии Мартина Р., это определено в стандарте 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, такие прогнозы могут быть неверными. Это применимо, если вы прогнозируете порядок байтов .

Но, как правило, вы должны использовать стандарт Юникода, который гласит, что если BOM не найден, вы должны обращаться с байтами как с прямым порядком байтов.

...