将十六进制数据字符串转换为 Objective C 中的 NSData (cocoa)

发布于 2024-08-22 20:33:20 字数 615 浏览 7 评论 0原文

这里是相当新的 iPhone 开发人员。构建一个应用程序,通过 TCP/IP 套接字连接将 RS232 命令发送到需要这些命令的设备。我已经把通讯部分搞定了,可以很好地发送 ASCII 命令。这是我遇到问题的十六进制代码命令。

假设我要发送以下十六进制数据(以这种格式):

\x1C\x02d\x00\x00\x00\xFF\x7F

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

显然,这不适用于此十六进制数据(但适用于标准 ascii 命令):

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

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

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

有什么想法吗?

fairly new iPhone developer here. Building an app to send RS232 commands to a device expecting them over a TCP/IP socket connection. I've got the comms part down, and can send ASCII commands fine. It's the hex code commands I'm having trouble with.

So lets say I have the following hex data to send (in this format):

\x1C\x02d\x00\x00\x00\xFF\x7F

How do I convert this into an NSData object, which my send method expects?

Obviously this does not work for this hex data (but does for standard ascii commands):

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

For a start, some of the \x hex codes are escape characters, and I get an "input conversion stopped..." warning when compiling in XCode. And NSStringEncoding obviously isn't right for this hex string either.

So the first problem is how to store this hex string I guess, then how to convert to NSData.

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

陪你到最终 2024-08-29 20:33:20

NSString 中的十六进制代码,例如“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);

Code for hex in NSStrings like "00 05 22 1C EA 01 00 FF". 'command' is the hex 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);
辞慾 2024-08-29 20:33:20

下面是在 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

Here's an example decoder implemented on a category on 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
柠檬心 2024-08-29 20:33:20

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

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 的变量中,并且 lengthOfInputData的长度>输入数据):


#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];
}

If you can hard code the hex data:

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];

If your code must interpret the hex string (assuming the hex string is in a variable called inputData and lengthOfInputData is the length of inputData):


#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];
}
ㄟ。诗瑗 2024-08-29 20:33:20

这是一个老话题了,但我想补充几点。

• 使用[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];
}

This is an old topic, but I'd like to add some remarks.

• Scanning a string with [NSString characterAtIndex] is not very efficient.
Get the C string in UTF8, then scan it using a *char++ is much faster.

• It's better to allocate NSMutableData with capacity, to avoid time consuming block resizing. I think NSData is even better ( see next point )

• Instead of create NSData using malloc, then [NSData dataWithBytes] and finally free, use malloc, and [NSData dataWithBytesNoCopy:length:freeWhenDone:]

It also avoids memory operation ( reallocate, copy, free ). The freeWhenDone boolean tells the NSData to take ownership of the memory block, and free it when it will be released.

• Here is the function I have to convert hex strings to bytes blocks. There is not much error checking on input string, but the allocation is tested.

The formatting of the input string ( like remove 0x, spaces and punctuation marks ) is better out of the conversion function.
Why would we lose some time doing extra processing if we are sure the input is OK.

+(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];
}
泪是无色的血 2024-08-29 20:33:20

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

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

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

显然这不适用于此十六进制数据(但适用于标准 ascii 命令):

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

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

首先,它是 Xcode,带有小写的 c。

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

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

If I want to hard-code the bytes, I do something like this:

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

If you're obtaining these backslash-escaped bytes at run time, try the strunvis function.

Obviously this does not work for this hex data (but does for standard ascii commands):

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

For a start, some of the \x hex codes are escape characters, and I get an "input conversion stopped..." warning when compiling in XCode. And NSStringEncoding obviously isn't right for this hex string either.

First, it's Xcode, with a lowercase c.

Second, NSStringEncoding is a type, not an encoding identifier. That code shouldn't compile at all.

More to the point, backslash-escaping is not an encoding; in fact, it's largely independent of encoding. The backslash and 'x' are characters, not bytes, which means that they must be encoded to (and decoded from) bytes, which is the job of an encoding.

夏有森光若流苏 2024-08-29 20:33:20

另一种方法可以做到这一点。

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

Another way to do it.

-(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;
}
枕花眠 2024-08-29 20:33:20
-(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;
}
-(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;
}
横笛休吹塞上声 2024-08-29 20:33:20

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

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

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

I know this is a very old thread, but there is an encoding scheme in Objective C that can easily convert your string of hex codes into ASCII characters.

1) remove the \x from the string and with out keeping spaces in the string just convert the string to NSData using :

[[NSData alloc] initWithData:[stringToBeConverted dataUsingEncoding:NSASCIIStringEncoding]];
能怎样 2024-08-29 20:33:20

十六进制数据只是内存中的字节,您将其视为字符串,因为这就是您看到的方式,但它们可以代表任何内容。
尝试:(在浏览器中输入,可能包含错误)

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

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

等...

Hex data is just bytes in memory, you think of it as a string because that's how you see it but they could represent anything.
Try: (typed in the browser, may contain errors)

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

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

etc...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文