在Swift中将十六进制字符串转换为NSData

时间:2023-01-05 18:51:57

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

我得到了在Objective-C中将String转换为HEX-String的代码。

- (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 anybody translate this code in Swift, or is there any easy way to do this in Swift?

我想在Swift中也一样。任何人都可以在Swift中翻译这段代码,还是有任何简单的方法在Swift中执行此操作?

6 个解决方案

#1


74  

This is my hex string to Data routine:

这是我对数据例程的十六进制字符串:

extension String {

    /// Create `Data` from hexadecimal string representation
    ///
    /// This takes a hexadecimal representation and creates a `Data` 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.
    ///
    /// - returns: Data represented by this hexadecimal string.

    func hexadecimal() -> Data? {
        var data = Data(capacity: characters.count / 2)

        let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .caseInsensitive)
        regex.enumerateMatches(in: self, range: NSMakeRange(0, utf16.count)) { match, flags, stop in
            let byteString = (self as NSString).substring(with: match!.range)
            var num = UInt8(byteString, radix: 16)!
            data.append(&num, count: 1)
        }

        guard data.count > 0 else { return nil }

        return data
    }

}

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

为了完整起见,这是我的数据到十六进制字符串例程:

extension Data {

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

    func hexadecimal() -> String {
        return map { String(format: "%02x", $0) }
            .joined(separator: "")
    }
}

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:

注意,如上所示,我通常只在十六进制表示和NSData实例之间进行转换(因为如果信息可能已经表示为字符串,您可能不会首先创建十六进制表示)。但是你原来的问题想要在十六进制表示和String对象之间进行转换,这可能是这样的:

extension String {

    /// Create `String` representation of `Data` created from hexadecimal string representation
    ///
    /// This takes a hexadecimal representation and creates a String object from that. 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.
    ///
    /// For example,
    ///
    ///     String(hexadecimal: "<666f6f>")
    ///
    /// is
    ///
    ///     Optional("foo")
    ///
    /// - returns: `String` represented by this hexadecimal string.

    init?(hexadecimal string: String, encoding: String.Encoding = .utf8) {
        guard let data = string.hexadecimal() else {
            return nil
        }

        self.init(data: data, encoding: encoding)
    }

    /// Create hexadecimal string representation of `String` object.
    ///
    /// For example,
    ///
    ///     "foo".hexadecimalString()
    ///
    /// is
    ///
    ///     Optional("666f6f")
    ///
    /// - parameter encoding: The `String.Encoding` that indicates how the string should be converted to `Data` before performing the hexadecimal conversion.
    ///
    /// - returns: `String` representation of this String object.

    func hexadecimalString(encoding: String.Encoding = .utf8) -> String? {
        return data(using: encoding)?
            .hexadecimal()
    }

}

You could then use the above like so:

然后你就可以使用上面这样的:

let hexString = "68656c6c 6f2c2077 6f726c64"
print(String(hexadecimal: hexString))

Or,

要么,

let originalString = "hello, world"
print(originalString.hexadecimalString())

For permutations of the above for earlier Swift versions, see the revision history of this question.

有关早期Swift版本的上述排列,请参阅此问题的修订历史记录。

#2


16  

convert hex string to data and string:

将十六进制字符串转换为数据和字符

Swift1

SWIFT1

func dataWithHexString(hex: String) -> NSData {
    var hex = hex
    let data = NSMutableData()
    while(countElements(hex) > 0) {
        var c: String = hex.substringToIndex(advance(hex.startIndex, 2))
        hex = hex.substringFromIndex(advance(hex.startIndex, 2))
        var ch: UInt32 = 0
        NSScanner(string: c).scanHexInt(&ch)
        data.appendBytes(&ch, length: 1)
    }
    return data
}

use:

使用:

let data = dataWithHexString("68656c6c6f2c20776f726c64") // <68656c6c 6f2c2077 6f726c64>
if let string = NSString(data: data, encoding: 1) {
    print(string) // hello, world
}

Swift2

Swift2

func dataWithHexString(hex: String) -> NSData {
    var hex = hex
    let data = NSMutableData()
    while(hex.characters.count > 0) {
        let c: String = hex.substringToIndex(hex.startIndex.advancedBy(2))
        hex = hex.substringFromIndex(hex.startIndex.advancedBy(2))
        var ch: UInt32 = 0
        NSScanner(string: c).scanHexInt(&ch)
        data.appendBytes(&ch, length: 1)
    }
    return data
}

use:

使用:

let data = dataWithHexString("68656c6c6f2c20776f726c64") // <68656c6c 6f2c2077 6f726c64>
if let string = String(data: data, encoding: NSUTF8StringEncoding) {
    print(string) //"hello, world"
}

Swift3

Swift3

func dataWithHexString(hex: String) -> Data {
    var hex = hex
    var data = Data()
    while(hex.characters.count > 0) {
        let c: String = hex.substring(to: hex.index(hex.startIndex, offsetBy: 2))
        hex = hex.substring(from: hex.index(hex.startIndex, offsetBy: 2))
        var ch: UInt32 = 0
        Scanner(string: c).scanHexInt32(&ch)
        var char = UInt8(ch)
        data.append(&char, count: 1)
    }
    return data
}

use:

使用:

let data = dataWithHexString(hex: "68656c6c6f2c20776f726c64") // <68656c6c 6f2c2077 6f726c64>
let string = String(data: data, encoding: .utf8) // "hello, world"

Swift4

Swift4

func dataWithHexString(hex: String) -> Data {
    var hex = hex
    var data = Data()
    while(hex.count > 0) {
        let subIndex = hex.index(hex.startIndex, offsetBy: 2)
        let c = String(hex[..<subIndex])
        hex = String(hex[subIndex...])
        var ch: UInt32 = 0
        Scanner(string: c).scanHexInt32(&ch)
        var char = UInt8(ch)
        data.append(&char, count: 1)
    }
    return data
}

use:

使用:

let data = dataWithHexString(hex: "68656c6c6f2c20776f726c64") // <68656c6c 6f2c2077 6f726c64>
let string = String(data: data, encoding: .utf8) // "hello, world"

#3


6  

Swift 4 implementation:

Swift 4实现:

extension Data {
    init?(hexString: String) {
        let len = hexString.count / 2
        var data = Data(capacity: len)
        for i in 0..<len {
            let j = hexString.index(hexString.startIndex, offsetBy: i*2)
            let k = hexString.index(j, offsetBy: 2)
            let bytes = hexString[j..<k]
            if var num = UInt8(bytes, radix: 16) {
                data.append(&num, count: 1)
            } else {
                return nil
            }
        }
        self = data
    }
}

Usage:

用法:

let data = Data(hexString: "0a1b3c4d")

#4


2  

Here's a simple solution I settled on:

这是我解决的一个简单的解决方案:

extension NSData {
    public convenience init(hexString: String) {
        var index = hexString.startIndex
        var bytes: [UInt8] = []
        repeat {
            bytes.append(hexString[index...index.advancedBy(1)].withCString {
                return UInt8(strtoul($0, nil, 16))
            })

            index = index.advancedBy(2)
        } while index.distanceTo(hexString.endIndex) != 0

        self.init(bytes: &bytes, length: bytes.count)
    }
}

Usage:

用法:

let data = NSData(hexString: "b8dfb080bc33fb564249e34252bf143d88fc018f")

Output:

输出:

print(data)
>>> <b8dfb080 bc33fb56 4249e342 52bf143d 88fc018f>

Update 6/29/2016

I updated the initializer to handle malformed data (i.e., invalid characters or odd number of characters).

我更新了初始化程序以处理格式错误的数据(即无效字符或奇数字符)。

public convenience init?(hexString: String, force: Bool) {
    let characterSet = NSCharacterSet(charactersInString: "0123456789abcdefABCDEF")
    for scalar in hexString.unicodeScalars {
        if characterSet.characterIsMember(UInt16(scalar.value)) {
            hexString.append(scalar)
        }
        else if !force {
            return nil
        }
    }

    if hexString.characters.count % 2 == 1 {
        if force {
            hexString = "0" + hexString
        }
        else {
            return nil
        }
    }

    var index = hexString.startIndex
    var bytes: [UInt8] = []
    repeat {
        bytes.append(hexString[index...index.advancedBy(1)].withCString {
            return UInt8(strtoul($0, nil, 16))
            })

        index = index.advancedBy(2)
    } while index.distanceTo(hexString.endIndex) != 0

    self.init(bytes: &bytes, length: bytes.count)
}

#5


0  

The code worked for me in Swift 3.0.2.

该代码在Swift 3.0.2中为我工作。

extension String {
    /// Expanded encoding
    ///
    /// - bytesHexLiteral: Hex string of bytes
    /// - base64: Base64 string
    enum ExpandedEncoding {
        /// Hex string of bytes
        case bytesHexLiteral
        /// Base64 string
        case base64
    }

    /// Convert to `Data` with expanded encoding
    ///
    /// - Parameter encoding: Expanded encoding
    /// - Returns: data
    func data(using encoding: ExpandedEncoding) -> Data? {
        switch encoding {
        case .bytesHexLiteral:
            guard self.characters.count % 2 == 0 else { return nil }
            var data = Data()
            var byteLiteral = ""
            for (index, character) in self.characters.enumerated() {
                if index % 2 == 0 {
                    byteLiteral = String(character)
                } else {
                    byteLiteral.append(character)
                    guard let byte = UInt8(byteLiteral, radix: 16) else { return nil }
                    data.append(byte)
                }
            }
            return data
        case .base64:
            return Data(base64Encoded: self)
        }
    }
}

#6


-2  

The only thing you need from Rob's code is this:

Rob的代码中唯一需要的是:

extension NSData {
    func toHexString() -> String {

        var string = NSMutableString(capacity: length * 2)
        var byte: UInt8 = 0

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

        return string as String
    }
}

Then do

然后做

yourdataobject.toHexString()

To get the binary data as a hex string. Assuming yourdataobject is of type NSData.

将二进制数据作为十六进制字符串。假设你的数据对象是NSData类型。

#1


74  

This is my hex string to Data routine:

这是我对数据例程的十六进制字符串:

extension String {

    /// Create `Data` from hexadecimal string representation
    ///
    /// This takes a hexadecimal representation and creates a `Data` 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.
    ///
    /// - returns: Data represented by this hexadecimal string.

    func hexadecimal() -> Data? {
        var data = Data(capacity: characters.count / 2)

        let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .caseInsensitive)
        regex.enumerateMatches(in: self, range: NSMakeRange(0, utf16.count)) { match, flags, stop in
            let byteString = (self as NSString).substring(with: match!.range)
            var num = UInt8(byteString, radix: 16)!
            data.append(&num, count: 1)
        }

        guard data.count > 0 else { return nil }

        return data
    }

}

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

为了完整起见,这是我的数据到十六进制字符串例程:

extension Data {

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

    func hexadecimal() -> String {
        return map { String(format: "%02x", $0) }
            .joined(separator: "")
    }
}

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:

注意,如上所示,我通常只在十六进制表示和NSData实例之间进行转换(因为如果信息可能已经表示为字符串,您可能不会首先创建十六进制表示)。但是你原来的问题想要在十六进制表示和String对象之间进行转换,这可能是这样的:

extension String {

    /// Create `String` representation of `Data` created from hexadecimal string representation
    ///
    /// This takes a hexadecimal representation and creates a String object from that. 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.
    ///
    /// For example,
    ///
    ///     String(hexadecimal: "<666f6f>")
    ///
    /// is
    ///
    ///     Optional("foo")
    ///
    /// - returns: `String` represented by this hexadecimal string.

    init?(hexadecimal string: String, encoding: String.Encoding = .utf8) {
        guard let data = string.hexadecimal() else {
            return nil
        }

        self.init(data: data, encoding: encoding)
    }

    /// Create hexadecimal string representation of `String` object.
    ///
    /// For example,
    ///
    ///     "foo".hexadecimalString()
    ///
    /// is
    ///
    ///     Optional("666f6f")
    ///
    /// - parameter encoding: The `String.Encoding` that indicates how the string should be converted to `Data` before performing the hexadecimal conversion.
    ///
    /// - returns: `String` representation of this String object.

    func hexadecimalString(encoding: String.Encoding = .utf8) -> String? {
        return data(using: encoding)?
            .hexadecimal()
    }

}

You could then use the above like so:

然后你就可以使用上面这样的:

let hexString = "68656c6c 6f2c2077 6f726c64"
print(String(hexadecimal: hexString))

Or,

要么,

let originalString = "hello, world"
print(originalString.hexadecimalString())

For permutations of the above for earlier Swift versions, see the revision history of this question.

有关早期Swift版本的上述排列,请参阅此问题的修订历史记录。

#2


16  

convert hex string to data and string:

将十六进制字符串转换为数据和字符

Swift1

SWIFT1

func dataWithHexString(hex: String) -> NSData {
    var hex = hex
    let data = NSMutableData()
    while(countElements(hex) > 0) {
        var c: String = hex.substringToIndex(advance(hex.startIndex, 2))
        hex = hex.substringFromIndex(advance(hex.startIndex, 2))
        var ch: UInt32 = 0
        NSScanner(string: c).scanHexInt(&ch)
        data.appendBytes(&ch, length: 1)
    }
    return data
}

use:

使用:

let data = dataWithHexString("68656c6c6f2c20776f726c64") // <68656c6c 6f2c2077 6f726c64>
if let string = NSString(data: data, encoding: 1) {
    print(string) // hello, world
}

Swift2

Swift2

func dataWithHexString(hex: String) -> NSData {
    var hex = hex
    let data = NSMutableData()
    while(hex.characters.count > 0) {
        let c: String = hex.substringToIndex(hex.startIndex.advancedBy(2))
        hex = hex.substringFromIndex(hex.startIndex.advancedBy(2))
        var ch: UInt32 = 0
        NSScanner(string: c).scanHexInt(&ch)
        data.appendBytes(&ch, length: 1)
    }
    return data
}

use:

使用:

let data = dataWithHexString("68656c6c6f2c20776f726c64") // <68656c6c 6f2c2077 6f726c64>
if let string = String(data: data, encoding: NSUTF8StringEncoding) {
    print(string) //"hello, world"
}

Swift3

Swift3

func dataWithHexString(hex: String) -> Data {
    var hex = hex
    var data = Data()
    while(hex.characters.count > 0) {
        let c: String = hex.substring(to: hex.index(hex.startIndex, offsetBy: 2))
        hex = hex.substring(from: hex.index(hex.startIndex, offsetBy: 2))
        var ch: UInt32 = 0
        Scanner(string: c).scanHexInt32(&ch)
        var char = UInt8(ch)
        data.append(&char, count: 1)
    }
    return data
}

use:

使用:

let data = dataWithHexString(hex: "68656c6c6f2c20776f726c64") // <68656c6c 6f2c2077 6f726c64>
let string = String(data: data, encoding: .utf8) // "hello, world"

Swift4

Swift4

func dataWithHexString(hex: String) -> Data {
    var hex = hex
    var data = Data()
    while(hex.count > 0) {
        let subIndex = hex.index(hex.startIndex, offsetBy: 2)
        let c = String(hex[..<subIndex])
        hex = String(hex[subIndex...])
        var ch: UInt32 = 0
        Scanner(string: c).scanHexInt32(&ch)
        var char = UInt8(ch)
        data.append(&char, count: 1)
    }
    return data
}

use:

使用:

let data = dataWithHexString(hex: "68656c6c6f2c20776f726c64") // <68656c6c 6f2c2077 6f726c64>
let string = String(data: data, encoding: .utf8) // "hello, world"

#3


6  

Swift 4 implementation:

Swift 4实现:

extension Data {
    init?(hexString: String) {
        let len = hexString.count / 2
        var data = Data(capacity: len)
        for i in 0..<len {
            let j = hexString.index(hexString.startIndex, offsetBy: i*2)
            let k = hexString.index(j, offsetBy: 2)
            let bytes = hexString[j..<k]
            if var num = UInt8(bytes, radix: 16) {
                data.append(&num, count: 1)
            } else {
                return nil
            }
        }
        self = data
    }
}

Usage:

用法:

let data = Data(hexString: "0a1b3c4d")

#4


2  

Here's a simple solution I settled on:

这是我解决的一个简单的解决方案:

extension NSData {
    public convenience init(hexString: String) {
        var index = hexString.startIndex
        var bytes: [UInt8] = []
        repeat {
            bytes.append(hexString[index...index.advancedBy(1)].withCString {
                return UInt8(strtoul($0, nil, 16))
            })

            index = index.advancedBy(2)
        } while index.distanceTo(hexString.endIndex) != 0

        self.init(bytes: &bytes, length: bytes.count)
    }
}

Usage:

用法:

let data = NSData(hexString: "b8dfb080bc33fb564249e34252bf143d88fc018f")

Output:

输出:

print(data)
>>> <b8dfb080 bc33fb56 4249e342 52bf143d 88fc018f>

Update 6/29/2016

I updated the initializer to handle malformed data (i.e., invalid characters or odd number of characters).

我更新了初始化程序以处理格式错误的数据(即无效字符或奇数字符)。

public convenience init?(hexString: String, force: Bool) {
    let characterSet = NSCharacterSet(charactersInString: "0123456789abcdefABCDEF")
    for scalar in hexString.unicodeScalars {
        if characterSet.characterIsMember(UInt16(scalar.value)) {
            hexString.append(scalar)
        }
        else if !force {
            return nil
        }
    }

    if hexString.characters.count % 2 == 1 {
        if force {
            hexString = "0" + hexString
        }
        else {
            return nil
        }
    }

    var index = hexString.startIndex
    var bytes: [UInt8] = []
    repeat {
        bytes.append(hexString[index...index.advancedBy(1)].withCString {
            return UInt8(strtoul($0, nil, 16))
            })

        index = index.advancedBy(2)
    } while index.distanceTo(hexString.endIndex) != 0

    self.init(bytes: &bytes, length: bytes.count)
}

#5


0  

The code worked for me in Swift 3.0.2.

该代码在Swift 3.0.2中为我工作。

extension String {
    /// Expanded encoding
    ///
    /// - bytesHexLiteral: Hex string of bytes
    /// - base64: Base64 string
    enum ExpandedEncoding {
        /// Hex string of bytes
        case bytesHexLiteral
        /// Base64 string
        case base64
    }

    /// Convert to `Data` with expanded encoding
    ///
    /// - Parameter encoding: Expanded encoding
    /// - Returns: data
    func data(using encoding: ExpandedEncoding) -> Data? {
        switch encoding {
        case .bytesHexLiteral:
            guard self.characters.count % 2 == 0 else { return nil }
            var data = Data()
            var byteLiteral = ""
            for (index, character) in self.characters.enumerated() {
                if index % 2 == 0 {
                    byteLiteral = String(character)
                } else {
                    byteLiteral.append(character)
                    guard let byte = UInt8(byteLiteral, radix: 16) else { return nil }
                    data.append(byte)
                }
            }
            return data
        case .base64:
            return Data(base64Encoded: self)
        }
    }
}

#6


-2  

The only thing you need from Rob's code is this:

Rob的代码中唯一需要的是:

extension NSData {
    func toHexString() -> String {

        var string = NSMutableString(capacity: length * 2)
        var byte: UInt8 = 0

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

        return string as String
    }
}

Then do

然后做

yourdataobject.toHexString()

To get the binary data as a hex string. Assuming yourdataobject is of type NSData.

将二进制数据作为十六进制字符串。假设你的数据对象是NSData类型。