NSString (hex) to bytes

2019-01-04 11:24发布

Is there any method in Objective-C that converts a hex string to bytes? For example @"1156FFCD3430AA22" to an unsigned char array {0x11, 0x56, 0xFF, ...}.

7条回答
欢心
2楼-- · 2019-01-04 11:27

Several solution is returned wrong value if the string like this "DBA"

The correct data for "DBA" string is "\x0D\xBA" (int value : 3514)

if you got a data is not like this "\x0D\xBA" it mean you got a wrong byte because the value will be different, for example you got data like this "\xDB\x0A" the int value is 56074

Here is rewrite the solution:

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

}
查看更多
你好瞎i
3楼-- · 2019-01-04 11:31

Fastest NSString category implementation that I could think of (cocktail of some examples):

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

It is close to 8 times faster than wookay's solution. NSScanner is quite slow.

查看更多
再贱就再见
4楼-- · 2019-01-04 11:34

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

Or, as an extension on 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
    }
}

This is a continuous work-in-progress, but appears to work well so far.

Further optimizations and a more in-depth discussion can be found on Code Review.

查看更多
Bombasti
5楼-- · 2019-01-04 11:42

Not in the way you are doing it. You'll need to write your own method to take every two characters, interpret them as an int, and store them in an array.

查看更多
戒情不戒烟
6楼-- · 2019-01-04 11:51

The scanHexInt: and similar methods of NSScanner might be helpful in doing what you want, but you'd probably need to break the string up into smaller chunks first, in which case doing the translation manually might be simpler than using NSScanner.

查看更多
做自己的国王
7楼-- · 2019-01-04 11:51

Modified approach,

/* 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 = @"0123456789abcdefABCDEF";
    NSCharacterSet *hexc = [NSCharacterSet characterSetWithCharactersInString:hexChars];
    NSCharacterSet *invalidHexc = [hexc invertedSet];
    NSString * allHex = [[output componentsSeparatedByCharactersInSet:invalidHexc] componentsJoinedByString:@""];
    return allHex;
}
查看更多
登录 后发表回答