我有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。
答案 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,则应将字节视为大字节序。