在目标C中将十六进制数据字符串转换为NSData(可可)

时间:2010-02-26 01:40:26

标签: iphone objective-c cocoa hex nsdata

相当新的iPhone开发人员。构建一个应用程序,通过TCP / IP套接字连接向设备发送RS232命令。我已经将通信部分关闭,并且可以发送ASCII命令。这是我遇到问题的十六进制代码命令。

所以我想说我要发送以下十六进制数据(采用这种格式):

\ X1C \ x02d \ X00 \ X00 \ X00 \ XFF \ 0x7F部分

如何将其转换为我的send方法所期望的NSData对象?

显然这对于​​这个十六进制数据不起作用(但是对于标准的ascii命令也是如此):

NSString *commandascii;
NSData *commandToSend;
commandascii = @"\x1C\x02d\x00\x00\x00\xFF\x7F";
commandToSend = [commandascii dataUsingEncoding:NSStringEncoding];

首先,一些\ x十六进制代码是转义字符,在XCode中编译时,我收到“输入转换已停止...”警告。并且NSStringEncoding显然不适合这个十六进制字符串。

所以第一个问题是如何存储这个十六进制字符串我猜,然后如何转换为NSData。

有什么想法吗?

9 个答案:

答案 0 :(得分:30)

NSStrings中的十六进制代码,如“00 05 22 1C EA 01 00 FF”。 'command'是十六进制NSString。

command = [command stringByReplacingOccurrencesOfString:@" " withString:@""];
NSMutableData *commandToSend= [[NSMutableData alloc] init];
unsigned char whole_byte;
char byte_chars[3] = {'\0','\0','\0'};
for (int 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 :(得分:9)

这是在NSString上的类别上实现的示例解码器。

#import <stdio.h>
#import <stdlib.h>
#import <string.h>

unsigned char strToChar (char a, char b)
{
    char encoder[3] = {'\0','\0','\0'};
    encoder[0] = a;
    encoder[1] = b;
    return (char) strtol(encoder,NULL,16);
}

@interface NSString (NSStringExtensions)
- (NSData *) decodeFromHexidecimal;
@end

@implementation NSString (NSStringExtensions)

- (NSData *) decodeFromHexidecimal;
{
    const char * bytes = [self cStringUsingEncoding: NSUTF8StringEncoding];
    NSUInteger length = strlen(bytes);
    unsigned char * r = (unsigned char *) malloc(length / 2 + 1);
    unsigned char * index = r;

    while ((*bytes) && (*(bytes +1))) {
        *index = strToChar(*bytes, *(bytes +1));
        index++;
        bytes+=2;
    }
    *index = '\0';

    NSData * result = [NSData dataWithBytes: r length: length / 2];
    free(r);

    return result;
}

@end

答案 2 :(得分:4)

如果您可以硬编码十六进制数据:

const char bytes[] = "\x00\x12\x45\xAB";
size_t length = (sizeof bytes) - 1; //string literals have implicit trailing '\0'

NSData *data = [NSData dataWithBytes:bytes length:length];

如果您的代码必须解释十六进制字符串(假设十六进制字符串位于名为inputData的变量中,并且lengthOfInputDatainputData的长度):


#define HexCharToNybble(x) ((char)((x > '9') ? tolower(x) - 'a' + 10 : x - '0') & 0xF)

int i;

NSMutableData *data = [NSMutableData data];

for (i = 0; i < lengthOfInputData;)
{
    char byteToAppend;

    if (i < (lengthOfInputData - 3) &&
        inputData[i+0] == '\\' &&
        inputData[i+1] == 'x' &&
        isxdigit(inputData[i+2]) &&
        isxdigit(inputData[i+3]))
    {
        byteToAppend = HexCharToNybble(inputData[i+2]) << 4 + HexCharToNybble(input[i+3]);
        i += 4;
    }
    else
    {
        byteToAppend = inputData[i];
        i += 1;
    }

    [data appendBytes:&byteToAppend length:1];
}

答案 3 :(得分:2)

这是一个古老的话题,但我想补充一些评论。

•使用[NSString characterAtIndex]扫描字符串效率不高。 获取UTF8中的C字符串,然后使用*char++进行扫描速度要快得多。

•最好分配NSMutableData容量,以避免耗时的块大小调整。我认为NSData更好(见下一点)

•不是使用malloc创建NSData,而是使用[NSData dataWithBytes]并最终免费,使用malloc和[NSData dataWithBytesNoCopy:length:freeWhenDone:]

它还避免了内存操作(重新分配,复制,免费)。 freeWhenDone布尔值告诉NSData获取内存块的所有权,并在释放时释放它。

•这是我将十六进制字符串转换为字节块的函数。输入字符串上没有太多错误检查,但是测试了分配。

输入字符串的格式(如删除0x,空格和标点符号)在转换函数之外更好。 如果我们确定输入正常,为什么我们会浪费一些时间进行额外处理。

+(NSData*)bytesStringToData:(NSString*)bytesString
{
    if (!bytesString || !bytesString.length) return NULL;
    // Get the c string
    const char *scanner=[bytesString cStringUsingEncoding:NSUTF8StringEncoding];
    char twoChars[3]={0,0,0};
    long bytesBlockSize = formattedBytesString.length/2;
    long counter = bytesBlockSize;
    Byte *bytesBlock = malloc(bytesBlockSize);
    if (!bytesBlock) return NULL;
    Byte *writer = bytesBlock;
    while (counter--) {
        twoChars[0]=*scanner++;
        twoChars[1]=*scanner++;
        *writer++ = strtol(twoChars, NULL, 16);
    }
    return[NSData dataWithBytesNoCopy:bytesBlock length:bytesBlockSize freeWhenDone:YES];
}

答案 4 :(得分:1)

如果我想对字节进行硬编码,我会这样做:

enum { numCommandBytes = 8 };
static const unsigned char commandBytes[numCommandBytes] = { 0x1c, 0x02, 'd', 0x0, 0x0, 0x0, 0xff, 0x7f };

如果您在运行时获取这些反斜杠转义字节,请尝试the strunvis function

  

显然这对于​​这个十六进制数据不起作用(但是对于标准的ascii命令也是如此):

NSString *commandascii;
NSData *commandToSend;
commandascii = @"\x1C\x02d\x00\x00\x00\xFF\x7F";
commandToSend = [commandascii dataUsingEncoding:NSStringEncoding];
     

首先,一些\x十六进制代码是转义字符,在XCode中编译时,我收到“输入转换停止...”警告。并且NSStringEncoding显然不适合这个十六进制字符串。

首先,它是Xcode,小写c。

其次,NSStringEncoding是一种类型,而不是编码标识符。该代码根本不应该编译。

更重要的是,反斜杠转义不是编码;事实上,它在很大程度上独立于编码。反斜杠和'x'是字符,而不是字节,这意味着必须将它们编码为(并从中解码)字节,这是编码的工作。

答案 5 :(得分:0)

另一种方法。

-(NSData *) dataFromHexString:(NSString *) hexstr
{
    NSMutableData *data = [[NSMutableData alloc] init];
    NSString *inputStr = [hexstr uppercaseString];

    NSString *hexChars = @"0123456789ABCDEF";

    Byte b1,b2;
    b1 = 255;
    b2 = 255;
    for (int i=0; i<hexstr.length; i++) {
        NSString *subStr = [inputStr substringWithRange:NSMakeRange(i, 1)];
        NSRange loc = [hexChars rangeOfString:subStr];

        if (loc.location == NSNotFound) continue;

        if (255 == b1) {
            b1 = (Byte)loc.location;
        }else {
            b2 = (Byte)loc.location;

            //Appending the Byte to NSData
            Byte *bytes = malloc(sizeof(Byte) *1);
            bytes[0] = ((b1<<4) & 0xf0) | (b2 & 0x0f);
            [data appendBytes:bytes length:1];

            b1 = b2 = 255;
        }
    }

    return data;
}

答案 6 :(得分:0)

-(NSData*) convertToByteArray:(NSString*) command {
    if (command == nil || command.length == 0) return nil;
    NSString *command1 = command;
    if(command1.length%2 != 0) {
        // to handle odd bytes like 1000 decimal = 3E8 with is of length = 3
        command1 = [NSString stringWithFormat:@"0%@",command1];
    }
    NSUInteger length = command1.length/2 ;
    NSMutableData *commandToSend = [[NSMutableData alloc] initWithLength:length];
    char byte_chars[3] = {'\0','\0','\0'};
    unsigned char whole_byte;
    for (int i=0; i<length; i++) {
        byte_chars[0] = [command1 characterAtIndex:i*2];
        byte_chars[1] = [command1 characterAtIndex:i*2+1];
        whole_byte = strtol(byte_chars, NULL, 16);
        [commandToSend appendBytes:&whole_byte length:1];
    }
    NSRange commandRange = NSMakeRange(commandToSend.length - length, length);
    NSData *result = [commandToSend subdataWithRange:commandRange];
    return result;
}

答案 7 :(得分:-1)

我知道这是一个非常古老的线程,但Objective C中有一个编码方案,可以轻松地将您的十六进制代码字符串转换为ASCII字符。

1)从字符串中删除\x并且不在字符串中保留空格只需将字符串转换为NSData,使用:

[[NSData alloc] initWithData:[stringToBeConverted dataUsingEncoding:NSASCIIStringEncoding]];

答案 8 :(得分:-3)

十六进制数据只是内存中的字节,你认为它是一个字符串,因为你是这样看的,但它们可以代表任何东西。 尝试:(在浏览器中键入,可能包含错误)

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

[hexData appendBytes: 0x1C];
[hexData appendBytes: 0x02D];

等...