Qadir Hussain Qadir Hussain - 6 months ago 572
Swift Question

Converting Hex String to NSData in Swift

I got the code to convert String to HEX-String in objective-C.

- (NSString *) CreateDataWithHexString:(NSString*)inputString
{
NSUInteger inLength = [inputString length];


unichar *inCharacters = alloca(sizeof(unichar) * inLength);
[inputString getCharacters:inCharacters range:NSMakeRange(0, inLength)];

UInt8 *outBytes = malloc(sizeof(UInt8) * ((inLength / 2) + 1));

NSInteger i, o = 0;
UInt8 outByte = 0;

for (i = 0; i < inLength; i++) {
UInt8 c = inCharacters[i];
SInt8 value = -1;

if (c >= '0' && c <= '9') value = (c - '0');
else if (c >= 'A' && c <= 'F') value = 10 + (c - 'A');
else if (c >= 'a' && c <= 'f') value = 10 + (c - 'a');

if (value >= 0) {
if (i % 2 == 1) {
outBytes[o++] = (outByte << 4) | value;
outByte = 0;
} else {
outByte = value;
}

} else {
if (o != 0) break;
}
}

NSData *a = [[NSData alloc] initWithBytesNoCopy:outBytes length:o freeWhenDone:YES];
NSString* newStr = [NSString stringWithUTF8String:[a bytes]];
return newStr;

}


I want the same in Swift. can any body translate this code in swift.
or is there any easy way to do this in swift.

Please help

Rob Rob
Answer

This is my hex string to NSData routine:

extension String {

    /// Create NSData from hexadecimal string representation
    ///
    /// This takes a hexadecimal representation and creates a NSData object. Note, if the string has any spaces or non-hex characters (e.g. starts with '<' and with a '>'), those are ignored and only hex characters are processed.
    ///
    /// The use of `strtoul` inspired by Martin R at http://stackoverflow.com/a/26284562/1271826
    ///
    /// - returns: NSData represented by this hexadecimal string.

    func dataFromHexadecimalString() -> NSData? {
        let data = NSMutableData(capacity: characters.count / 2)

        let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .CaseInsensitive)
        regex.enumerateMatchesInString(self, options: [], range: NSMakeRange(0, characters.count)) { match, flags, stop in
            let byteString = (self as NSString).substringWithRange(match!.range)
            let num = UInt8(byteString.withCString { strtoul($0, nil, 16) })
            data?.appendBytes([num], length: 1)
        }

        return data
    }
}

Note, the above is written for Swift 2.0. See the revision history of this answer if you want to see Swift 1.2 or 1.1 renditions.

And for the sake of completeness, this is my NSData to hex string routine:

extension NSData {

    /// Create hexadecimal string representation of NSData object.
    ///
    /// - returns: String representation of this NSData object.

    func hexadecimalString() -> String {
        var string = ""
        var byte: UInt8 = 0

        for i in 0 ..< length {
            getBytes(&byte, range: NSMakeRange(i, 1))
            string += String(format: "%02x", byte)
        }

        return string
    }
}

Note, as shown in the above, I generally only convert between hexadecimal representations and NSData instances (because if the information could have been represented as a string you probably wouldn't have created a hexadecimal representation in the first place). But your original question wanted to convert between hexadecimal representations and String objects, and that might look like so:

extension String {

    /// Create NSData from hexadecimal string representation
    ///
    /// This takes a hexadecimal representation and creates a String object from taht. Note, if the string has any spaces, those are removed. Also if the string started with a '<' or ended with a '>', those are removed, too.
    ///
    /// - parameter encoding: The NSStringCoding that indicates how the binary data represented by the hex string should be converted to a String.
    ///
    /// - returns: String represented by this hexadecimal string. Returns nil if string contains characters outside the 0-9 and a-f range or if a string cannot be created using the provided encoding

    func stringFromHexadecimalStringUsingEncoding(encoding: NSStringEncoding) -> String? {
        if let data = dataFromHexadecimalString() {
            return String(data: data, encoding: encoding)
        }

        return nil
    }

    /// Create hexadecimal string representation of String object.
    ///
    /// - parameter encoding: The NSStringCoding that indicates how the string should be converted to NSData before performing the hexadecimal conversion.
    ///
    /// - returns: String representation of this String object.

    func hexadecimalStringUsingEncoding(encoding: NSStringEncoding) -> String? {
        let data = dataUsingEncoding(NSUTF8StringEncoding)
        return data?.hexadecimalString()
    }

}

You could then use the above like so:

let hexString = "68656c6c 6f2c2077 6f726c64"
print(hexString.stringFromHexadecimalStringUsingEncoding(NSUTF8StringEncoding))

Or,

let originalString = "hello, world"
print(originalString.hexadecimalStringUsingEncoding(NSUTF8StringEncoding))