hex/binary string conversion in Swift

独自空忆成欢 提交于 2019-11-26 19:12:52
Martin R

Data from Swift 3 has no "built-in" method to print its contents as a hex string, or to create a Data value from a hex string.

"Data to hex string" methods can be found e.g. at How to convert Data to hex string in swift or How to print the content of a variable type Data using swift? or converting string to data in swift 3.0. Here is an implementation from the first link:

extension Data {
    func hexEncodedString() -> String {
        return map { String(format: "%02hhx", $0) }.joined()
    }
}

Here is a possible implementation of the reverse "hex string to Data" conversion (taken from Hex String to Bytes (NSData) on Code Review, translated to Swift 3 and improved) as a failable inititializer:

extension Data {

    init?(fromHexEncodedString string: String) {

        // Convert 0 ... 9, a ... f, A ...F to their decimal value,
        // return nil for all other input characters
        func decodeNibble(u: UInt16) -> UInt8? {
            switch(u) {
            case 0x30 ... 0x39:
                return UInt8(u - 0x30)
            case 0x41 ... 0x46:
                return UInt8(u - 0x41 + 10)
            case 0x61 ... 0x66:
                return UInt8(u - 0x61 + 10)
            default:
                return nil
            }
        }

        self.init(capacity: string.utf16.count/2)
        var even = true
        var byte: UInt8 = 0
        for c in string.utf16 {
            guard let val = decodeNibble(u: c) else { return nil }
            if even {
                byte = val << 4
            } else {
                byte += val
                self.append(byte)
            }
            even = !even
        }
        guard even else { return nil }
    }
}

Example:

// Hex string to Data:
if let data = Data(fromHexEncodedString: "0002468A13579BFF") {
    let idata = Data(data.map { 255 - $0 })

    // Data to hex string:
    print(idata.hexEncodedString()) // fffdb975eca86400
} else {
    print("invalid hex string")
}

Not really familiar with Python and the checks it performs when convert the numbers, but you can expand the function below:

func convert(_ str: String, fromRadix r1: Int, toRadix r2: Int) -> String? {
    if let num = Int(str, radix: r1) {
        return String(num, radix: r2)
    } else {
        return nil
    }
}

convert("11111111", fromRadix: 2, toRadix: 16)
convert("ff", fromRadix: 16, toRadix: 2)

Swift 2

extension NSData {
    class func dataFromHexString(hex: String) -> NSData? {
        let regex = try! NSRegularExpression(pattern: "^[0-9a-zA-Z]*$", options: .CaseInsensitive)
        let validate = regex.firstMatchInString(hex, options: NSMatchingOptions.init(rawValue: 0), range: NSRange(location: 0, length: hex.characters.count))
        if validate == nil || hex.characters.count % 2 != 0 {
            return nil
        }
        let data = NSMutableData()
        for i in 0..<hex.characters.count/2 {
            let hexStr = hex.substring(i * 2, length: 2)
            var ch: UInt32 = 0
            NSScanner(string: hexStr).scanHexInt(&ch)
            data.appendBytes(&ch, length: 1)
        }
        return data
    }
}

let a = 0xabcd1234
print(String(format: "%x", a)) // Hex to String
NSData.dataFromHexString("abcd1234") // String to hex
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!