将十六进制的NSString转换为NSData

44

我正在尝试将一个十六进制的 NSString 转换为 NSData (我使用了下面附带的代码)。以下是输出结果:

<00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000>

这对我来说看起来完全不相关。你有什么想法/建议,在哪里可能出了问题?

NSString *strData = @"72ff63cea198b3edba8f7e0c23acc345050187a0cde5a9872cbab091ab73e553";

NSLog(@"string Data length is %d",[strData length]);

NSMutableData *commandToSend= [[NSMutableData alloc] init];
unsigned char whole_byte;
char byte_chars[2];
int i;
for (i=0; i < [strData length]/2; i++) {

    byte_chars[0] = [strData characterAtIndex:i*2];
    byte_chars[1] = [strData characterAtIndex:i*2+1];
    whole_byte = strtol(byte_chars, NULL, [strData length]);
    [commandToSend appendBytes:&whole_byte length:1]; 
}
NSLog(@"%@", commandToSend);    

你应该不将16传递给strtol吗? - Praveen S
4个回答

70
NSString *command = @"72ff63cea198b3edba8f7e0c23acc345050187a0cde5a9872cbab091ab73e553";

command = [command stringByReplacingOccurrencesOfString:@" " withString:@""];
NSMutableData *commandToSend= [[NSMutableData alloc] init];
unsigned char whole_byte;
char byte_chars[3] = {'\0','\0','\0'};
int i;
for (i=0; i < [command length]/2; i++) {
    byte_chars[0] = [command characterAtIndex:i*2];
    byte_chars[1] = [command characterAtIndex:i*2+1];
    whole_byte = strtol(byte_chars, NULL, 16);
    [commandToSend appendBytes:&whole_byte length:1]; 
}
NSLog(@"%@", commandToSend);

1
你得到了什么输出? - Pranav Jaiswal
2
它返回的是<72ff63ce a198b3ed ba8f7e0c 23acc345 050187a0 cde5a987 2cbab091 ab73e553>。 - Nikunj Jadav
还有一个问题,为什么将整型指针作为第三个参数传递给strtol函数,并且值为16? - Pranav Jaiswal
4
好的回答。对于将NSData deviceToken的描述转换回NSData非常有用。 - MikeS
看起来我们得到的答案与我们要转换的字符串相同。但是如何将该字符串数据转换为有用的信息呢?我的意思是,在扫描BLE设备后,我获得了广告数据,例如 kCBAdvDataManufacturerData = <ffff0215 e84a40af 7b8de88d 4a7b40af afe84a40 40af7b8d c3>;。现在从这个数据中,如何进行转换以便访问其数据。我想从给定的数据中找出Major Minor TxPower,我们应该如何做到这一点?@NikunjJadav - Moxarth
@NikunjJadav,我也提出了这个问题[https://stackoverflow.com/questions/45854508/how-to-decode-the-ble-advertisement-data/45859742?noredirect=1#comment78727814_45859742]。请看一下并指导我。谢谢。 - Moxarth

31

这里还有一种方法,也能处理前导 <、尾随 > 和嵌入空格,例如

<9dc69faf a7434ba9 aef57f5c 365d571f 4c3753c4 ae13db42 57d184ca e00246c5>

代码:

+ (NSData *)dataFromHexString:(NSString *)string
{
    string = [string lowercaseString];
    NSMutableData *data= [NSMutableData new];
    unsigned char whole_byte;
    char byte_chars[3] = {'\0','\0','\0'};
    int i = 0;
    int length = string.length;
    while (i < length-1) {
        char c = [string characterAtIndex:i++];
        if (c < '0' || (c > '9' && c < 'a') || c > 'f')
            continue;
        byte_chars[0] = c;
        byte_chars[1] = [string characterAtIndex:i++];
        whole_byte = strtol(byte_chars, NULL, 16);
        [data appendBytes:&whole_byte length:1];
    }
    return data;
}
这是基于@Nikunj R. Jadav的回答。

8

这可能更有用,苹果分享了一个NSData类别。

NSData+HexString.m

代码如下:

@implementation NSData (HexString)

// Not efficent
+(id)dataWithHexString:(NSString *)hex
{
    char buf[3];
    buf[2] = '\0';
    NSAssert(0 == [hex length] % 2, @"Hex strings should have an even number of digits (%@)", hex);
    unsigned char *bytes = malloc([hex length]/2);
    unsigned char *bp = bytes;
    for (CFIndex i = 0; i < [hex length]; i += 2) {
        buf[0] = [hex characterAtIndex:i];
        buf[1] = [hex characterAtIndex:i+1];
        char *b2 = NULL;
        *bp++ = strtol(buf, &b2, 16);
        NSAssert(b2 == buf + 2, @"String should be all hex digits: %@ (bad digit around %d)", hex, i);
    }

    return [NSData dataWithBytesNoCopy:bytes length:[hex length]/2 freeWhenDone:YES];
}

@end

通过调用malloc()动态分配的内存在...行后不可访问。
return [NSData dataWithBytesNoCopy:bytes length:[hex length]/2 freeWhenDone:YES];
- Benny Davidovitz

1

我看到有几个解决方案只能转换偶数长度的字符串。

所以这是我的解决方案,如果字符串长度为奇数也能返回正确的数据,就像这样"DBA"变成了这样的数据 "\x0D\xBA"

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

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接