versiones mac framework macos cocoa

macos - mac - ¿Cómo convertir un NSData en una cadena de Hex de NSString?



ios cocoa touch (8)

Cuando llamo -description en un objeto NSData , veo una bonita secuencia hexadecimal de los bytes del objeto NSData como:

<f6e7cd28 0fc5b5d4 88f8394b af216506 bc1bba86 4d5b483d>

Me gustaría obtener esta representación de los datos (menos las comillas lt / gt) en una NSString en memoria para que pueda trabajar con ella. Preferiría no llamar -[NSData description] y luego recortar el Cotizaciones de lt / gt (porque asumo que no es un aspecto garantizado de la interfaz pública de NSData y es un cambio sujeto en el futuro).

¿Cuál es la forma más sencilla de obtener esta representación de un objeto NSData en un objeto NSString (que no sea llamar a -description )?


Al ver que hay un fragmento de Swift 1.2 en los comentarios, esta es la versión de Swift 2, ya que el estilo C para los bucles ahora está en desuso. Gist con licencia de MIT y dos pruebas simples de unidad si te importa.

Aquí está el código para su conveniencia:

import Foundation extension NSData { var hexString: String { let pointer = UnsafePointer<UInt8>(bytes) let array = getByteArray(pointer) return array.reduce("") { (result, byte) -> String in result.stringByAppendingString(String(format: "%02x", byte)) } } private func getByteArray(pointer: UnsafePointer<UInt8>) -> [UInt8] { let buffer = UnsafeBufferPointer<UInt8>(start: pointer, count: length) return [UInt8](buffer) } }


En Swift puedes crear una extensión.

extension NSData { func toHexString() -> String { var hexString: String = "" let dataBytes = UnsafePointer<CUnsignedChar>(self.bytes) for (var i: Int=0; i<self.length; ++i) { hexString += String(format: "%02X", dataBytes[i]) } return hexString } }

Entonces puedes simplemente usar:

let keyData: NSData = NSData(bytes: [0x00, 0xFF], length: 2) let hexString = keyData.toHexString() println("/(hexString)") // Outputs 00FF


Estoy de acuerdo con la solución de no llamar a la description que debe reservarse para la depuración, por lo tanto, buen punto y buena pregunta :)

La solución más fácil es recorrer los bytes del NSData y construir el NSString a partir de él. Utilice [yourData bytes] para acceder a los bytes y NSMutableString la cadena en un NSMutableString .

Aquí hay un ejemplo implementando esto usando una categoría de NSData

@interface NSData(Hex) -(NSString*)hexRepresentationWithSpaces_AS:(BOOL)spaces; @end @implementation NSData(Hex) -(NSString*)hexRepresentationWithSpaces_AS:(BOOL)spaces { const unsigned char* bytes = (const unsigned char*)[self bytes]; NSUInteger nbBytes = [self length]; //If spaces is true, insert a space every this many input bytes (twice this many output characters). static const NSUInteger spaceEveryThisManyBytes = 4UL; //If spaces is true, insert a line-break instead of a space every this many spaces. static const NSUInteger lineBreakEveryThisManySpaces = 4UL; const NSUInteger lineBreakEveryThisManyBytes = spaceEveryThisManyBytes * lineBreakEveryThisManySpaces; NSUInteger strLen = 2*nbBytes + (spaces ? nbBytes/spaceEveryThisManyBytes : 0); NSMutableString* hex = [[NSMutableString alloc] initWithCapacity:strLen]; for(NSUInteger i=0; i<nbBytes; ) { [hex appendFormat:@"%02X", bytes[i]]; //We need to increment here so that the every-n-bytes computations are right. ++i; if (spaces) { if (i % lineBreakEveryThisManyBytes == 0) [hex appendString:@"/n"]; else if (i % spaceEveryThisManyBytes == 0) [hex appendString:@" "]; } } return [hex autorelease]; } @end

Uso:

NSData* data = ... NSString* hex = [data hexRepresentationWithSpaces_AS:YES];


Lamentablemente, no existe una forma integrada de producir hexadecimal a partir de un NSData, pero es bastante fácil hacerlo tú mismo. La forma simple es simplemente pasar bytes sucesivos a sprintf ("% 02x") y acumularlos en un NSMutableString. Una manera más rápida sería construir una tabla de búsqueda que mapee 4 bits en un carácter hexadecimal, y luego pasar sucesivos nybbles en esa tabla.


Me gustó la respuesta de @ Erik_Aigner lo mejor. Acabo de refactorarlo un poco:

NSData *data = [NSMutableData dataWithBytes:"acani" length:5]; NSUInteger dataLength = [data length]; NSMutableString *string = [NSMutableString stringWithCapacity:dataLength*2]; const unsigned char *dataBytes = [data bytes]; for (NSInteger idx = 0; idx < dataLength; ++idx) { [string appendFormat:@"%02x", dataBytes[idx]]; }


Si bien puede no ser la manera más eficiente de hacerlo, si está haciendo esto para la depuración, SSCrypto tiene una categoría en NSData que contiene dos métodos para hacerlo (uno para crear un NSString de los valores de bytes sin formato, y otro que muestra una representación más bonita de él).

http://www.septicus.com/SSCrypto/trunk/SSCrypto.m


Solo quería agregar que el método de @ PassKits se puede escribir muy elegantemente usando Swift 3 ya que Data ahora es una colección.

extension Data { var hex: String { var hexString = "" for byte in self { hexString += String(format: "%02X", byte) } return hexString } }

O ...

extension Data { var hex: String { return self.map { b in String(format: "%02X", b) }.joined() } }

O incluso ...

extension Data { var hex: String { return self.reduce("") { string, byte in string + String(format: "%02X", byte) } } }


Tenga en cuenta que cualquier solución String(format: ...) será terriblemente lenta (para datos de gran tamaño)

NSData *data = ...; NSUInteger capacity = data.length * 2; NSMutableString *sbuf = [NSMutableString stringWithCapacity:capacity]; const unsigned char *buf = data.bytes; NSInteger i; for (i=0; i<data.length; ++i) { [sbuf appendFormat:@"%02X", (NSUInteger)buf[i]]; }

Si necesita algo más productivo, intente esto:

static inline char itoh(int i) { if (i > 9) return ''A'' + (i - 10); return ''0'' + i; } NSString * NSDataToHex(NSData *data) { NSUInteger i, len; unsigned char *buf, *bytes; len = data.length; bytes = (unsigned char*)data.bytes; buf = malloc(len*2); for (i=0; i<len; i++) { buf[i*2] = itoh((bytes[i] >> 4) & 0xF); buf[i*2+1] = itoh(bytes[i] & 0xF); } return [[NSString alloc] initWithBytesNoCopy:buf length:len*2 encoding:NSASCIIStringEncoding freeWhenDone:YES]; }

Swift 3 versión

extension NSData { var hexString: String? { let buf = bytes.assumingMemoryBound(to: UInt8.self) let charA = UInt8(UnicodeScalar("a").value) let char0 = UInt8(UnicodeScalar("0").value) func itoh(_ value: UInt8) -> UInt8 { return (value > 9) ? (charA + value - 10) : (char0 + value) } let hexLen = length * 2 let ptr = UnsafeMutablePointer<UInt8>.allocate(capacity: hexLen) for i in 0 ..< length { ptr[i*2] = itoh((buf[i] >> 4) & 0xF) ptr[i*2+1] = itoh(buf[i] & 0xF) } return String(bytesNoCopy: ptr, length: hexLen, encoding: .utf8, freeWhenDone: true) } }