2016-10-18 5 views
0

Мне нужно кодировать строку в UTF-16LE (и конвертировать в sha1 позже), но у меня возникают некоторые проблемы. Это то, что я пробовал:Swift 3: кодировать строку в UTF-16LE

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({ $0 as UInt8 }) 
// [112, 97, 115, 115, 119, 111, 114, 100] 

Итак, это то, что я сделал " исправить ":

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] 

Но я «Конечно, это не правильный путь. Какие-либо предложения?

+1

Содержимое массива UTF-16 - это все 16-разрядные целые числа, поэтому те 0 байтов, которые вы ожидаете, уже включены в каждое значение. Вы изменили данные, вставив эти дополнительные нули (которые также составляют 16 бит). –

ответ

5

Вы можете получить представление в виде данных 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($0, CC_LONG(data.count), &digest) 
} 
let hexEncodedDigest = digest.map { String(format: "%02hhx", $0) }.joined() 
print(hexEncodedDigest) 
// 177f0d080dfe533e102dd67d6321204813cf1b0c 

Но если вам это нужно как массив байтов, то

let bytesArray = data.map { $0 } 
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 { 
    $0.baseAddress!.withMemoryRebound(to: UInt8.self, capacity: 2 * utf16array.count) { 
     UnsafeBufferPointer(start: $0, count: 2 * utf16array.count) 
    } 
}) 
print(bytes) 
// [112, 0, 97, 0, 115, 0, 115, 0, 119, 0, 111, 0, 114, 0, 100, 0, 172, 32] 
+0

Ты рок! Это именно то, что я искал. Работал как шарм. Спасибо. – hdoria

0

Использование String to Data method data(using:) подходит для решения задач здесь.

Но для удовольствия, альтернативного использования решений в String: ами UTF-16 кодирование подхода (utf16 свойства String) в ОП. Использование init(truncatingBitPattern: UInt16) инициализатора UInt8, в сочетании с zip сопровождаемым flatMap, последнее уплощением архивных кортежей в массив:

let pw = "password€" 

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

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

Что об использовании cString accessor?

var bytes = str.cStringUsingEncoding(NSUTF16LittleEndianStringEncoding) 
Смежные вопросы