Swift 3:将字符串编码为UTF-16LE

Swift 3: Encode String to UTF-16LE

我需要将字符串编码为 UTF-16LE(稍后再转换为 sha1),但我遇到了一些问题。这是我试过的:

let utf16array = Array("password".utf16)
print(utf16array)
// [112, 97, 115, 115, 119, 111, 114, 100]

但这正是我所期待的:

// [112, 0, 97, 0, 115, 0, 115, 0, 119, 0, 111, 0, 114, 0, 100, 0] 

同样使用 utf8array:

let utf8array = "password".utf8.map({ [=13=] as UInt8 })
// [112, 97, 115, 115, 119, 111, 114, 100]

所以,这就是我对 "fix" 所做的:

var bytesArray:[UInt16] = []
for byte in utf16array {
    bytesArray.append(byte)
    bytesArray.append(0)
}
print(bytesArray)
// [112, 0, 97, 0, 115, 0, 115, 0, 119, 0, 111, 0, 114, 0, 100, 0]

但我敢肯定这不是正确的方法。有什么建议吗?

使用 是适合这里目的的解决方案。

但为了好玩,另一种方法是使用 String:s UTF-16 编码方法(Stringutf16 属性) OP。使用 UInt8init(truncatingBitPattern: UInt16) 初始值设定项,结合 zip 后跟 flatMap,后者将压缩元组展平为数组:

let pw = "password€"

let bytes = zip(pw.utf16.map{ UInt8(truncatingBitPattern: [=10=]) },
                pw.utf16.map{ UInt8(truncatingBitPattern: [=10=] >> 8) })
            .flatMap{ [[=10=], ] }

print(bytes)
// [112, 0, 97, 0, 115, 0, 115, 0, 119, 0, 111, 0, 114, 0, 100, 0, 172, 32]

您可以使用

获得 UTF-16LE 数据的表示形式
let password = "password€"
let data = password.data(using: .utf16LittleEndian)!
print(data as NSData)
// <70006100 73007300 77006f00 72006400 ac20>

这已经足以计算 SHA1 摘要(代码 来自 How to crypt string to sha1 with Swift?):

var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH))
data.withUnsafeBytes { 
    _ = CC_SHA1([=11=], CC_LONG(data.count), &digest)
}
let hexEncodedDigest = digest.map { String(format: "%02hhx", [=11=]) }.joined()
print(hexEncodedDigest)
// 177f0d080dfe533e102dd67d6321204813cf1b0c

但是如果你需要它作为一个字节数组那么

let bytesArray = data.map { [=12=] }
print(bytesArray)
// [112, 0, 97, 0, 115, 0, 115, 0, 119, 0, 111, 0, 114, 0, 100, 0, 172, 32]

会起作用。

(为了演示,我附加了一个非ASCII字符, € = U+20AC 变成 172, 32.)


如果您想知道如何将 [UInt16] 数组转换为 [UInt8] 数组,这就是你可以通过一些指针杂耍来做到这一点的方法 (只有一个副本):

let utf16array = Array("password€".utf16)
print(utf16array)
// [112, 97, 115, 115, 119, 111, 114, 100, 8364]

let bytes = Array(utf16array.withUnsafeBufferPointer {
    [=13=].baseAddress!.withMemoryRebound(to: UInt8.self, capacity: 2 * utf16array.count) {
        UnsafeBufferPointer(start: [=13=], count: 2 * utf16array.count)
    }
})
print(bytes)
// [112, 0, 97, 0, 115, 0, 115, 0, 119, 0, 111, 0, 114, 0, 100, 0, 172, 32]

使用 cString 访问器怎么样?

var bytes = str.cStringUsingEncoding(NSUTF16LittleEndianStringEncoding)