2010-03-23 21 views
17

¿Hay algún método en Objective-C que convierta una cadena hexadecimal en bytes? Por ejemplo @"1156FFCD3430AA22" a unsigned char array {0x11, 0x56, 0xFF, ...}.NSString (hex) a bytes

Respuesta

2

No en la forma en que lo está haciendo. Tendrá que escribir su propio método para tomar cada dos caracteres, interpretarlos como un int, y almacenarlos en una matriz.

3

Los scanHexInt: y métodos similares de NSScanner podrían ser útiles en hacer lo que quiera, pero que probablemente tenga que romper la cadena en trozos más pequeños primero, en cuyo caso, haciendo la traducción manual podría ser más simple que el uso de NSScanner.

21
@interface NSString (NSStringHexToBytes) 
-(NSData*) hexToBytes ; 
@end 



@implementation NSString (NSStringHexToBytes) 
-(NSData*) hexToBytes { 
    NSMutableData* data = [NSMutableData data]; 
    int idx; 
    for (idx = 0; idx+2 <= self.length; idx+=2) { 
    NSRange range = NSMakeRange(idx, 2); 
    NSString* hexStr = [self substringWithRange:range]; 
    NSScanner* scanner = [NSScanner scannerWithString:hexStr]; 
    unsigned int intValue; 
    [scanner scanHexInt:&intValue]; 
    [data appendBytes:&intValue length:1]; 
    } 
    return data; 
} 
@end 



/// example 
unsigned char bytes[] = { 0x11, 0x56, 0xFF, 0xCD, 0x34, 0x30, 0xAA, 0x22 }; 
NSData* expectedData = [NSData dataWithBytes:bytes length:sizeof(bytes)]; 
NSLog(@"data %@", [@"1156FFCD3430AA22" hexToBytes]); 
NSLog(@"expectedData isEqual:%d", [expectedData isEqual:[@"1156FFCD3430AA22" hexToBytes]]); 
+5

me corrija si estoy equivocado, pero creo que los [appendBytes de datos: & intValue longitud: 1] tiene algunos problemas. Tipo unsigned int tiene al menos cuatro caracteres de ancho (contiene al menos 32 bit). & intValue es un puntero al primero de los cuatro. Esto significa que en el sistema little endian, & intValue será un puntero al char que acaba de escanear. Pero en las arquitecturas de big endian siempre apunta a un valor cero, porque el valor se almacena como el último de los cuatro caracteres. Básicamente, esto significa que este código funcionará en Mac y romperá en iOS. – Trenskow

+2

Esta respuesta tiene bastantes defectos. No solo trata el 'int' como si fuera un byte (lo cual es imposible de acuerdo con el estándar C), sino que solo genera superfluo muchas subcadenas, en lugar de solo caminar a través del' const char * 'que se puede obtener usando 'UTF8String' ... –

1

enfoque modificado,

/* Converts a hex string to bytes. 
Precondition: 
. The hex string can be separated by space or not. 
. the string length without space or 0x, must be even. 2 symbols for one byte/char 
. sample input: 23 3A F1 OR 233AF1, 0x23 0X231f 2B 
*/ 

+ (NSData *) dataFromHexString:(NSString*)hexString 
{ 
    NSString * cleanString = [Util cleanNonHexCharsFromHexString:hexString]; 
    if (cleanString == nil) { 
     return nil; 
    } 

    NSMutableData *result = [[NSMutableData alloc] init]; 

    int i = 0; 
    for (i = 0; i+2 <= cleanString.length; i+=2) { 
     NSRange range = NSMakeRange(i, 2); 
     NSString* hexStr = [cleanString substringWithRange:range]; 
     NSScanner* scanner = [NSScanner scannerWithString:hexStr]; 
     unsigned int intValue; 
     [scanner scanHexInt:&intValue]; 
     unsigned char uc = (unsigned char) intValue; 
     [result appendBytes:&uc length:1]; 
    } 
    NSData * data = [NSData dataWithData:result]; 
    [result release]; 
    return data; 
} 

/* Clean a hex string by removing spaces and 0x chars. 
. The hex string can be separated by space or not. 
. sample input: 23 3A F1; 233AF1; 0x23 0x3A 0xf1 
*/ 

+ (NSString *) cleanNonHexCharsFromHexString:(NSString *)input 
{ 
    if (input == nil) { 
     return nil; 
    } 

    NSString * output = [input stringByReplacingOccurrencesOfString:@"0x" withString:@"" 
            options:NSCaseInsensitiveSearch range:NSMakeRange(0, input.length)]; 
    NSString * hexChars = @"abcdefABCDEF"; 
    NSCharacterSet *hexc = [NSCharacterSet characterSetWithCharactersInString:hexChars]; 
    NSCharacterSet *invalidHexc = [hexc invertedSet]; 
    NSString * allHex = [[output componentsSeparatedByCharactersInSet:invalidHexc] componentsJoinedByString:@""]; 
    return allHex; 
} 
39

más rápido NSString categoría de aplicación que lo que podía pensar (cóctel de algunos ejemplos):

- (NSData *)dataFromHexString { 
    const char *chars = [self UTF8String]; 
    int i = 0, len = self.length; 

    NSMutableData *data = [NSMutableData dataWithCapacity:len/2]; 
    char byteChars[3] = {'\0','\0','\0'}; 
    unsigned long wholeByte; 

    while (i < len) { 
     byteChars[0] = chars[i++]; 
     byteChars[1] = chars[i++]; 
     wholeByte = strtoul(byteChars, NULL, 16); 
     [data appendBytes:&wholeByte length:1]; 
    } 

    return data; 
} 

Está cerca de 8 veces más rápido que la solución de wookay . NSScanner es bastante lento.

+3

+1 esto parece ser mejor, no solo más rápido, pero esto es ** realmente correcto.** –

+0

Muy buena implementación. –

+0

Buena implementación, pero si necesita verificar errores, debe establecer 'errno' en 0 antes de llamar a 'strtoul' y leerlo después. – Joe

0

primer intento en Swift 2.2:

func hexStringToBytes(hexString: String) -> NSData? { 
    guard let chars = hexString.cStringUsingEncoding(NSUTF8StringEncoding) else { return nil} 
    var i = 0 
    let length = hexString.characters.count 

    let data = NSMutableData(capacity: length/2) 
    var byteChars: [CChar] = [0, 0, 0] 

    var wholeByte: CUnsignedLong = 0 

    while i < length { 
     byteChars[0] = chars[i] 
     i+=1 
     byteChars[1] = chars[i] 
     i+=1 
     wholeByte = strtoul(byteChars, nil, 16) 
     data?.appendBytes(&wholeByte, length: 1) 
    } 

    return data 
} 

O, como una extensión de la secuencia:

extension String { 

    func dataFromHexString() -> NSData? { 
     guard let chars = cStringUsingEncoding(NSUTF8StringEncoding) else { return nil} 
     var i = 0 
     let length = characters.count 

     let data = NSMutableData(capacity: length/2) 
     var byteChars: [CChar] = [0, 0, 0] 

     var wholeByte: CUnsignedLong = 0 

     while i < length { 
      byteChars[0] = chars[i] 
      i+=1 
      byteChars[1] = chars[i] 
      i+=1 
      wholeByte = strtoul(byteChars, nil, 16) 
      data?.appendBytes(&wholeByte, length: 1) 
     } 

     return data 
    } 
} 

Este es un trabajo en progreso continuo, pero parece funcionar bien hasta ahora.

Más optimizaciones y un debate más en profundidad se pueden encontrar en Code Review.

+0

¿No se trata simplemente de una traducción de Swift de [esta respuesta] (http://stackoverflow.com/a/17511588/865175)? –

0

varios solución se devuelve un valor incorrecto si la cadena como esta "DBA"

los datos correctos para "DBA" cadena es "\ x0D \ XBA" (valor int: 3514)

si tienes un dato no es así "\ x0D \ XBA" significa que tienes un byte mal porque el valor será diferente, por ejemplo, usted tiene los datos como éste "\ xDB \ x0A" el int valor es 56074

Aquí es reescribir la solución:

+ (NSData *)dataFromHexString:(NSString *) string { 
    if([string length] % 2 == 1){ 
     string = [@"0"stringByAppendingString:string]; 
    } 

    const char *chars = [string UTF8String]; 
    int i = 0, len = (int)[string length]; 

    NSMutableData *data = [NSMutableData dataWithCapacity:len/2]; 
    char byteChars[3] = {'\0','\0','\0'}; 
    unsigned long wholeByte; 

    while (i < len) { 
     byteChars[0] = chars[i++]; 
     byteChars[1] = chars[i++]; 
     wholeByte = strtoul(byteChars, NULL, 16); 
     [data appendBytes:&wholeByte length:1]; 
    } 
    return data; 

}