ios - 做 String.Encoding.utf16 和 String.Encoding。utf16BigEndian 表示相同的意思,即 UTF16BigEndian?
问题描述
我有一个用 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 应该是我的机器字节序。但根据我的测试,它是 bigendian 的。
解决方案
所以我的问题是,.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。)
似乎我的猜测是错误的,并且.utf16
在未找到 BOM 时,Apple's Foundation 更喜欢 Big Endian 而不是平台的本机字节序。(也许有一些历史原因,因为Apple曾经使用Big Endian平台,68k或Power-PC。正如Martin R的评论,它是在Unicode标准中定义的。似乎我需要更新我的知识。)
但是您应该更好地指定.utf16BigEndian
何时知道您的数据不包含 BOM 并在 Big Endian 中.utf16
指定包含正确 BOM 的数据。
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,您应该将字节视为大端。
推荐阅读
- javascript - Javascript 复选框显示错误
- swift - 在 Swift 中比较日期忽略当前时区
- java - org.apache.http.ContentTooLongException:实体内容太长 [105539255] 对于配置的缓冲区限制 [104857600]
- javascript - 如何删除从数组中选择的元素
- php - 如何显示我的 html 邮件?
- ios - 找到不支持的类型 - AVMetadataObject
- oracle - 从 query.getResultList 检索类时出现 Hibernate ClassCastException
- javascript - 通过 AJAX 将复选框 id 发布到 php
- ios - 在表视图之外传递和访问对象数据
- asp.net - 我想在 asp.net webforms 项目中进行时间同步