nshtmltextdocumenttype swift swift3

nshtmltextdocumenttype - Cómo convertir datos a una cadena hexadecimal en Swift



html in label swift (7)

Quiero la representación hexadecimal de un valor de datos en Swift.

Eventualmente me gustaría usarlo así:

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


Este código extiende el tipo de Data con una propiedad calculada. Se itera a través de los bytes de datos y concatena la representación hexadecimal del byte con el resultado:

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


Esto realmente no responde a la pregunta del OP ya que funciona en una matriz de bytes Swift, no en un objeto de datos. Y es mucho más grande que las otras respuestas. Pero debería ser más eficiente ya que evita usar String (format:).

De todos modos, con la esperanza de que alguien encuentre esto ú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 prueba:

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


Mi version. No es tan elegante, pero es aproximadamente 10 veces más rápido que la respuesta aceptada 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)]) })) } }


Sería una implementación alternativa (tomada de Cómo encriptar cadena a sha1 con Swift?, Con una opción adicional para salida en mayúscula)

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() } }

Elegí un hexEncodedString(options:) en el estilo del método existente base64EncodedString(options:) .

Data ajustan al protocolo de recopilación, por lo tanto, se puede usar map() para asignar cada byte a la cadena hexadecimal correspondiente. El formato %02x imprime el argumento en base 16, rellenado hasta dos dígitos con un cero a la %02x si es necesario. El modificador hh hace que el argumento (que se pasa como un entero en la pila) se trate como una cantidad de un byte. Uno podría omitir el modificador aquí porque $0 es un número sin signo ( UInt8 ) y no se producirá una extensión de signo, pero no hace daño dejarlo.

El resultado se une a una sola cadena.

Ejemplo:

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

La siguiente implementación es más rápida en un factor de aproximadamente 120 (probado con 1000 bytes aleatorios). Es similar a la solución de RenniePet y la solución de Nick Moore , pero se basa en unidades de código UTF-16, que es lo que las cadenas Swift (actualmente) usan como almacenamiento 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) } }


Tome cada byte y conviértalo a hexadecimal, luego añádalo al valor acumulado que comienza como una cadena vacía:

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


Quizás no sea el más rápido, pero data.map({ String($0, radix: 16) }).joined() hace el trabajo. Como se mencionó en los comentarios, esta solución fue defectuosa.


Swift 4: de datos a cadena hexadecimal
Basado en la solución de Martin R, pero incluso un poco más rápido.

extension Data { /// A hexadecimal string representation of the bytes. func hexEncodedString() -> String { let hexDigits = Array("0123456789abcdef".utf16) var hexChars = [UTF16.CodeUnit]() hexChars.reserveCapacity(count * 2) for byte in self { let (index1, index2) = Int(byte).quotientAndRemainder(dividingBy: 16) hexChars.append(hexDigits[index1]) hexChars.append(hexDigits[index2]) } return String(utf16CodeUnits: hexChars, count: hexChars.count) } }

Swift 4: de cadena hexadecimal a datos
También he agregado una solución rápida para convertir una cadena hexadecimal en datos (basada en una solución C ).

extension String { /// A data representation of the hexadecimal bytes in this string. func hexDecodedData() -> Data { // Get the UTF8 characters of this string let chars = Array(utf8) // Keep the bytes in an UInt8 array and later convert it to Data var bytes = [UInt8]() bytes.reserveCapacity(count / 2) // It is a lot faster to use a lookup map instead of strtoul let map: [UInt8] = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 01234567 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 89:;<=>? 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, // @ABCDEFG 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // HIJKLMNO ] // Grab two characters at a time, map them and turn it into a byte for i in stride(from: 0, to: count, by: 2) { let index1 = Int(chars[i] & 0x1F ^ 0x10) let index2 = Int(chars[i + 1] & 0x1F ^ 0x10) bytes.append(map[index1] << 4 | map[index2]) } return Data(bytes) } }

Nota: esta función no valida la entrada. Asegúrese de que solo se use para cadenas hexadecimales con (una cantidad par) de caracteres.