Como converter dados em uma cadeia hexadecimal em swift

Eu quero a representação hexadecimal de um valor de dados no Swift.

Eventualmente, eu gostaria de usá-lo assim:

let data = Data(base64Encoded: "aGVsbG8gd29ybGQ=")! print(data.hexString) 

Uma implementação alternativa (tirada de Como criptografar string para sha1 com Swift ? , com uma opção adicional para saída maiúscula) seria

 extension Data { struct HexEncodingOptions: OptionSet { let rawValue: Int static let upperCase = HexEncodingOptions(rawValue: 1 < < 0) } func hexEncodedString(options: HexEncodingOptions = []) -> String { let format = options.contains(.upperCase) ? "%02hhX" : "%02hhx" return map { String(format: format, $0) }.joined() } } 

Eu escolhi um hexEncodedString(options:) no estilo do método existente base64EncodedString(options:) .

Data estão de acordo com o protocolo Collection , portanto, é possível usar map() para mapear cada byte para a string hexadecimal correspondente. O formato %02x imprime o argumento na base 16, preenchido até dois dígitos com um zero à esquerda, se necessário. O modificador hh faz com que o argumento (que é passado como um inteiro na pilha) seja tratado como uma quantidade de um byte. Pode-se omitir o modificador aqui porque $0 é um número não assinado ( UInt8 ) e nenhuma extensão de sinal irá ocorrer, mas não faz mal deixá-lo UInt8 .

O resultado é então unido a uma única string.

Exemplo:

 let data = Data(bytes: [0, 1, 127, 128, 255]) print(data.hexEncodedString()) // 00017f80ff print(data.hexEncodedString(options: .upperCase)) // 00017F80FF 

A implementação a seguir é mais rápida por um fator de aproximadamente 120 (testado com 1000 bytes randoms). É semelhante à solução da RenniePet e à solução de Nick Moore , mas baseada em unidades de código UTF-16, que é o que as strings Swift (atualmente) usam como armazenamento interno.

 extension Data { struct HexEncodingOptions: OptionSet { let rawValue: Int static let upperCase = HexEncodingOptions(rawValue: 1 < < 0) } func hexEncodedString(options: HexEncodingOptions = []) -> String { let hexDigits = Array((options.contains(.upperCase) ? "0123456789ABCDEF" : "0123456789abcdef").utf16) var chars: [unichar] = [] chars.reserveCapacity(2 * count) for byte in self { chars.append(hexDigits[Int(byte / 16)]) chars.append(hexDigits[Int(byte % 16)]) } return String(utf16CodeUnits: chars, count: chars.count) } } 

Minha versão. Não é tão elegante, mas é cerca de 10 vezes mais rápido que a resposta aceita por Martin R.

 extension Data { private static let hexAlphabet = "0123456789abcdef".unicodeScalars.map { $0 } public func hexEncodedString() -> String { return String(self.reduce(into: "".unicodeScalars, { (result, value) in result.append(Data.hexAlphabet[Int(value/16)]) result.append(Data.hexAlphabet[Int(value%16)]) })) } } 

Este código estende o tipo de Data com uma propriedade calculada. Ele itera através dos bytes de dados e concatena a representação hexadecimal do byte para o resultado:

 extension Data { var hexDescription: String { return reduce("") {$0 + String(format: "%02x", $1)} } } 

Isso realmente não responde à pergunta do OP, pois funciona em uma matriz de bytes Swift, não em um object Data. E é muito maior que as outras respostas. Mas deve ser mais eficiente, pois evita usar String (format:).

De qualquer forma, na esperança de que alguém ache isso útil …

 public class StringMisc { // MARK: - Constants // This is used by the byteArrayToHexString() method private static let CHexLookup : [Character] = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" ] // Mark: - Public methods /// Method to convert a byte array into a string containing hex characters, without any /// additional formatting. public static func byteArrayToHexString(_ byteArray : [UInt8]) -> String { var stringToReturn = "" for oneByte in byteArray { let asInt = Int(oneByte) stringToReturn.append(StringMisc.CHexLookup[asInt >> 4]) stringToReturn.append(StringMisc.CHexLookup[asInt & 0x0f]) } return stringToReturn } } 

Caso de teste:

  // Test the byteArrayToHexString() method let byteArray : [UInt8] = [ 0x25, 0x99, 0xf3 ] assert(StringMisc.byteArrayToHexString(byteArray) == "2599F3")