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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26501276/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 03:17:23  来源:igfitidea点击:

Converting Hex String to NSData in Swift

iosobjective-cswift

提问by Qadir Hussain

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 中做到这一点?

回答by Rob

This is my hex string to Dataroutine:

这是我的十六进制字符串到Data例程:

extension String {

    /// Create `Data` from hexadecimal string representation
    ///
    /// This creates a `Data` object from hex string. 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.

    var 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: NSRange(startIndex..., in: self)) { match, _, _ in
            let byteString = (self as NSString).substring(with: match!.range)
            let num = UInt8(byteString, radix: 16)!
            data.append(num)
        }

        guard data.count > 0 else { return nil }

        return data
    }

}

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

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

extension Data {

    /// Hexadecimal string representation of `Data` object.

    var hexadecimal: String {
        return map { String(format: "%02x", 
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
    }

}
) } .joined() } }


Note, as shown in the above, I generally only convert between hexadecimal representations and NSDatainstances (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 Stringobjects, and that might look like so:

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

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

You could then use the above like so:

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

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

Or,

或者,

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
}

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

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

回答by larva

convert hex string to data and string:

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

Swift1

斯威夫特1

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

use:

用:

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
}

Swift2

斯威夫特2

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

use:

用:

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
}

Swift3

斯威夫特3

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

use:

用:

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
}

Swift4

斯威夫特4

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

use:

用:

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

回答by Rok Gregori?

Swift 4 & Swift 5implementation:

Swift 4 和 Swift 5实现:

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

Usage:

用法:

    extension String {
        enum ExtendedEncoding {
            case hexadecimal
        }

        func data(using encoding:ExtendedEncoding) -> Data? {
            let hexStr = self.dropFirst(self.hasPrefix("0x") ? 2 : 0)

            guard hexStr.count % 2 == 0 else { return nil }

            var newData = Data(capacity: hexStr.count/2)

            var indexIsEven = true
            for i in hexStr.indices {
                if indexIsEven {
                    let byteRange = i...hexStr.index(after: i)
                    guard let byte = UInt8(hexStr[byteRange], radix: 16) else { return nil }
                    newData.append(byte)
                }
                indexIsEven.toggle()
            }
            return newData
        }
    }

回答by itMaxence

Here is my Swifty 5way to do it:

这是我的Swifty 5方法:

  • does take care of "0x" prefixes
  • use subscript instead of allocated Array(), no C style [i+1] too
  • add .hexadecimalto String.data(using encoding:) -> Data?
  • 确实会处理“0x”前缀
  • 使用下标代替分配的 Array(),也没有 C 风格 [i+1]
  • 添加.hexadecimalString.data(using encoding:) -> Data?

.

.

String Extension:

字符串扩展:

    "5413".data(using: .hexadecimal)
    "0x1234FF".data(using: .hexadecimal)

Usage:

用法:

    extension Data {
        var bytes:[UInt8] { // fancy pretty call: myData.bytes -> [UInt8]
            return [UInt8](self)
        }

        // Could make a more optimized one~
        func hexa(prefixed isPrefixed:Bool = true) -> String {
            return self.bytes.reduce(isPrefixed ? "0x" : "") { 
extension Data {
    private static let hexRegex = try! NSRegularExpression(pattern: "^([a-fA-F0-9][a-fA-F0-9])*$", options: [])

    init?(hexString: String) {
        if Data.hexRegex.matches(in: hexString, range: NSMakeRange(0, hexString.count)).isEmpty {
            return nil // does not look like a hexadecimal string
        }

        let chars = Array(hexString)

        let bytes: [UInt8] = 
            stride(from: 0, to: chars.count, by: 2)
                .map {UInt8(String([chars[
    let data = Data(hexString: "cafecafe")

    print(data?.hexString) // will print Optional("cafecafe")
], chars[
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(
let data = NSData(hexString: "b8dfb080bc33fb564249e34252bf143d88fc018f")
, nil, 16)) }) index = index.advancedBy(2) } while index.distanceTo(hexString.endIndex) != 0 self.init(bytes: &bytes, length: bytes.count) } }
+1]]), radix: 16)} .compactMap{
print(data)
>>> <b8dfb080 bc33fb56 4249e342 52bf143d 88fc018f>
} self = Data(bytes) } var hexString: String { return map { String(format: "%02hhx",
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(
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)
        }
    }
}
, nil, 16)) }) index = index.advancedBy(2) } while index.distanceTo(hexString.endIndex) != 0 self.init(bytes: &bytes, length: bytes.count) }
) }.joined() } }
+ String(format: "%02X", ) } } } print("000204ff5400".data(using: .hexadecimal)?.hexa() ?? "failed") // OK print("0x000204ff5400".data(using: .hexadecimal)?.hexa() ?? "failed") // OK print("541".data(using: .hexadecimal)?.hexa() ?? "failed") // fails print("5413".data(using: .hexadecimal)?.hexa() ?? "failed") // OK

Tests:

测试:

extension String {
  var hex: Data? {
    var value = self
    var data = Data()

    while value.count > 0 {
      let subIndex = value.index(value.startIndex, offsetBy: 2)
      let c = String(value[..<subIndex])
      value = String(value[subIndex...])

      var char: UInt8
      if #available(iOS 13.0, *) {
        guard let int = Scanner(string: c).scanInt32(representation: .hexadecimal) else { return nil }
        char = UInt8(int)
      } else {
        var int: UInt32 = 0
        Scanner(string: c).scanHexInt32(&int)
        char = UInt8(int)
      }

      data.append(&char, count: 1)
    }

    return data
  }
}

回答by Peter Lamberg

Here is my take on converting hexadecimal string to Data using Swift 4:

这是我使用 Swift 4 将十六进制字符串转换为数据的看法:

func hex(from string: String) -> Data {
    .init(stride(from: 0, to: string.count, by: 2).map {
        string[string.index(string.startIndex, offsetBy: ##代码##) ... string.index(string.startIndex, offsetBy: ##代码## + 1)]
    }.map {
        UInt8(##代码##, radix: 16)!
    })
}

(I threw in a small feature for converting back to hex string I found in this answer)

(我加入了一个小功能,用于转换回我在这个答案中找到的十六进制字符串

And here is how you would use it:

这是您将如何使用它:

##代码##

回答by Dan Loewenherz

Here's a simple solution I settled on:

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

##代码##

Usage:

用法:

##代码##

Output:

输出:

##代码##

Update 6/29/2016

2016 年 6 月 29 日更新

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

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

##代码##

回答by jqgsninimo

The code worked for me in Swift 3.0.2.

该代码在Swift 3.0.2 中对我有用

##代码##

回答by dimpiax

Swift 5

斯威夫特 5

With support iOS 13and iOS2...iOS12.

支持iOS 13iOS2... iOS12

##代码##

回答by vauxhall

Supposing your string is even size, you can use this to convert to hexadecimal and save it to Data:

假设您的字符串是偶数大小,您可以使用它来转换为十六进制并将其保存到数据:

Swift 5.2

斯威夫特 5.2

##代码##