swift - 如何快速将数据转换为十六进制字符串

标签 swift swift3

我想要 Swift 中数据值的十六进制表示。

最终我想像这样使用它:

let data = Data(base64Encoded: "aGVsbG8gd29ybGQ=")!
print(data.hexString)

最佳答案

一个简单的实现(取自 How to hash NSString with SHA1 in Swift? ,带有大写输出的附加选项)是

extension Data {
    struct HexEncodingOptions: OptionSet {
        let rawValue: Int
        static let upperCase = HexEncodingOptions(rawValue: 1 << 0)
    }

    func hexEncodedString(options: HexEncodingOptions = []) -> String {
        let format = options.contains(.upperCase) ? "%02hhX" : "%02hhx"
        return self.map { String(format: format, $0) }.joined()
    }
}

我在现有方法 base64EncodedString(options:) 的样式中选择了一个 hexEncodedString(options:) 方法。

Data 符合 Collection 协议(protocol),因此可以使用 map() 将每个字节映射到相应的十六进制字符串。 %02x 格式以 16 进制打印参数,最多填充两位数 如有必要,使用前导零。 hh 修饰符导致参数 (在堆栈上作为整数传递)被视为一个字节 数量。这里可以省略修饰符,因为 $0 是一个 unsigned number (UInt8) 并且不会发生符号扩展,但离开也没有坏处

然后将结果连接到单个字符串。

例子:

let data = Data([0, 1, 127, 128, 255])
// For Swift < 4.2 use:
// let data = Data(bytes: [0, 1, 127, 128, 255])
print(data.hexEncodedString()) // 00017f80ff
print(data.hexEncodedString(options: .upperCase)) // 00017F80FF

以下实现速度提高了大约 50 倍 (用 1000 个随机字节测试)。它的灵感来自 RenniePet's solutionNick Moore's solution ,但利用 String(unsafeUninitializedCapacity:initializingUTF8With:) 它随 Swift 5.3/Xcode 12 一起引入,可在 macOS 11 和 iOS 14 或更高版本上使用。

此方法允许从 UTF-8 单元高效地创建 Swift 字符串,而无需不必要的复制或重新分配。

还提供了旧 macOS/iOS 版本的替代实现。

extension Data {
    struct HexEncodingOptions: OptionSet {
        let rawValue: Int
        static let upperCase = HexEncodingOptions(rawValue: 1 << 0)
    }

    func hexEncodedString(options: HexEncodingOptions = []) -> String {
        let hexDigits = options.contains(.upperCase) ? "0123456789ABCDEF" : "0123456789abcdef"
        if #available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) {
            let utf8Digits = Array(hexDigits.utf8)
            return String(unsafeUninitializedCapacity: 2 * self.count) { (ptr) -> Int in
                var p = ptr.baseAddress!
                for byte in self {
                    p[0] = utf8Digits[Int(byte / 16)]
                    p[1] = utf8Digits[Int(byte % 16)]
                    p += 2
                }
                return 2 * self.count
            }
        } else {
            let utf16Digits = Array(hexDigits.utf16)
            var chars: [unichar] = []
            chars.reserveCapacity(2 * self.count)
            for byte in self {
                chars.append(utf16Digits[Int(byte / 16)])
                chars.append(utf16Digits[Int(byte % 16)])
            }
            return String(utf16CodeUnits: chars, count: chars.count)
        }
    }
}

关于swift - 如何快速将数据转换为十六进制字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39075043/

相关文章:

ios - 我想在我的应用程序中使用分页。我有一个像这样的API :

string - 使用 Swift 中的 find/get 函数将字符串分成多个字符串

swift - 需要时如何将 Float 转换为 Int?

swift - 加载临时视频并播放

ios - 将值从 TableView Controller 传递到 View Controller

swift - 将 scanLocation 从 utf16 单位转换为 NSScanner (Swift) 中的字符索引

ios - 如何检测可操作通知的触发日期

swift - 无法访问全局常量文件中定义的枚举案例的原始值

ios - "Method does not override any method from its superclass" swift 3

json - 用 alamofire 改变编码体