2010-03-23 86 views

回答

2

不像你这样做。您需要编写自己的方法来获取每两个字符,将它们解释为一个int,然后将它们存储在一个数组中。

3

scanHexInt:NSScanner类似的方法可能是在做你想要什么有益的,但你可能会需要向上突破字符串成小块第一,在这种情况下做翻译手动可能会比使用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

纠正我,如果我错了,但我认为[数据对appendBytes:长的intValue:1]有一些麻烦。类型无符号整型至少有四个字符宽(至少保持32位)。 &intValue是指向四个中第一个的指针。这意味着,在小端系统中,&intValue将正确地成为您刚刚扫描的字符的指针。但在大端架构中,它始终指向一个零值,因为该值是作为四个字符中的最后一个存储的。基本上这意味着这段代码可以在Mac上运行并在iOS上破解。 – Trenskow 2012-08-22 23:45:59

+2

这个答案有很多缺陷。它不仅将int视为一个字节(根据C标准,这是不可能的),而且它仅仅会产生大量的子字符串,而不是仅仅遍历可以使用的'const char * 'UTF8String' ... – 2013-07-07 11:34:29

1

修订的方法,

/* 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
,我能想到的(一些例子鸡尾酒)的

最快的NSString类实现:

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

这是接近8倍的速度比wookay的解决方案。 NSScanner非常慢。在雨燕2.2

+3

+1这似乎更好 - 不仅更快,但这实际上是正确的。** – 2013-07-07 11:35:44

+0

非常好的实施。 – 2013-11-27 20:13:29

+0

好的实现,但如果你需要错误检查,你需要在调用'strtoul'之前将'errno'设置为0,然后再读取它。 – Joe 2017-10-17 01:16:01

0

第一次尝试:

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 
} 

或者,作为字符串的扩展:

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

这是一个持续的工作正在进行中,但似乎很好地工作至今。

进一步优化和更深入的讨论可以在Code Review找到。

+0

是不是这只是[这个答案](http://stackoverflow.com/a/17511588/865175)的Swift翻译? – 2016-11-23 17:36:33

0

几个溶液返回错误值,如果像这样 字符串 “DBA

正确为 “DBA” 数据串是“\ X0D \ XBA”(int值:3514)

,如果你有一个数据是不喜欢这个“\ X0D \ XBA”它意味着你有一个错误的字节,因为该值会有所不同,例如,你得到的数据是这样“\ XDB \ X0A”该int值是56074

这里是重写的解决方案:

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

}