2010-03-23 7 views
17

Gibt es eine Methode in Objective-C, die eine hexadezimale Zeichenfolge auf Bytes umwandelt? Zum Beispiel @"1156FFCD3430AA22" zu einem unsigned char array {0x11, 0x56, 0xFF, ...}.NSString (hex) auf Bytes

Antwort

2

Nicht so, wie Sie es tun. Sie müssen Ihre eigene Methode schreiben, um alle zwei Zeichen zu nehmen, sie als int zu interpretieren und sie in einem Array zu speichern.

3

Die scanHexInt: und ähnliche Methoden der NSScanner könnte hilfreich sein, zu tun, was Sie wollen, aber Sie würden wahrscheinlich brauchen die Zeichenfolge in kleinere Stücke, in denen zuerst zu brechen Fall macht die Übersetzung manuell einfacher sein könnte als NSScanner verwenden.

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

mich korrigieren, wenn ich falsch bin, aber ich denke, die [Daten appendBytes: & intValue Länge: 1] hat einige Probleme. Der Typ unsigned int ist mindestens vier Zeichen breit (mindestens 32 Bit lang). & intValue ist ein Zeiger auf den ersten der vier. Dies bedeutet, dass das & intValue auf Little-Endian-System zu Recht ein Zeiger auf das gerade gescannte Zeichen sein wird. Aber auf Big-Endian-Architekturen zeigt es immer auf einen Nullwert, weil der Wert als das letzte der vier Zeichen gespeichert wird. Grundsätzlich bedeutet dies, dass dieser Code auf Macs funktioniert und auf iOS bricht. – Trenskow

+2

Diese Antwort hat ziemlich viele Fehler. Es behandelt nicht nur das 'int', als ob es ein Byte wäre (was nach dem C-Standard unmöglich ist), sondern erzeugt nur überflüssig viele Teilzeichenfolgen, anstatt nur durch das 'const char *' zu gehen, das man benutzen kann 'UTF8String' ... –

1

Modified Ansatz,

/* 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

Schnellste NSString Kategorie Implementierung, die ich von (Cocktail einiger Beispiele) einfiel:

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

Es bis 8-mal der Nähe ist schneller als wookay-Lösung . NSScanner ist ziemlich langsam.

+3

+1 das scheint besser zu sein - nicht nur schneller, aber das ist eigentlich richtig.** –

+0

Sehr gute Implementierung. –

+0

Gute Implementierung, aber wenn Sie eine Fehlerüberprüfung benötigen, müssen Sie 'errno' auf 0 setzen, bevor Sie' strtoul' aufrufen und danach lesen. – Joe

0

Erster Versuch in 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 
} 

Oder als Erweiterung auf String:

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

Dies ist eine kontinuierliche Arbeit-in-progress, erscheint aber bisher gut zu arbeiten.

Weitere Optimierungen und eine tiefergehende Diskussion auf Code Review finden.

+0

Ist das nicht nur eine schnelle Übersetzung von [diese Antwort] (http://stackoverflow.com/a/17511588/865175)? –

0

Mehrere Lösung falschen Wert zurückgegeben, wenn die Zeichenfolge wie diese "DBA"

die richtigen Daten für "DBA" string ist "\ x0D \ Xba" (int value: 3514)

, wenn Sie bekommt ein Datum ist nicht wie dies „\ x0D \ XBA“ es bedeutet ein falsches Byte bekommen, weil der Wert wird anders sein, zum Beispiel können Sie Daten wie diese „\ xDB \ x0A“ bekamen das int Wert ist 56074

Hier ist die Lösung umschreiben:

+ (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; 

}