执行String.Encoding.utf16和String.Encoding。 utf16BigEndian的意思是同一件事,即UTF16BigEndian吗?

时间:2019-04-08 05:45:17

标签: ios swift xcode foundation

我有utf16 big endian编码的字符串的字节。这些字节由我从我的同事共享的文件中读取,该文件确认该字符串为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应该是我的机器字节序。但是根据我的测试,结果证明是bigendian。

1 个答案:

答案 0 :(得分:1)

所以我的问题是,.utf16和.utf16BigEndian是同一件事吗?

不。正确的UTF-16需要在文件顶部包含BOM。

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表示BOM的小尾数形式。在大尾数法中,它将是0xfe,0xff。

使用.utf16,即使在字节序不匹配的平台上,您也可以读取正确的UTF-16数据(我的意思是拥有正确的BOM)。

放入print(data as NSData)并检查data的前两个字节。我猜它包含0xfe,0xff(大字节序中的BOM。)


似乎我的猜测是错误的,并且在未找到BOM的情况下,Apple Foundation中的.utf16更喜欢Big Endian而不是平台的本机字节序。 (也许是历史原因,因为苹果公司曾经使用Big Endian平台,68k或Power-PC。正如Martin R的评论一样,它是在Unicode标准中定义的。似乎我需要刷新自己的知识)

但是,当您知道自己的数据不包含BOM时,最好使用.utf16BigEndian,在Big Endian中,对于包含正确BOM的数据,请指定.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标准,该标准指出如果找不到BOM,则应将字节视为大字节序。