I want the hexadecimal representation of a Data value in Swift.
我想要一个数据值的十六进制表示形式为Swift。
Eventually I'd want to use it like this:
最后我想这样使用它:
let data = Data(base64Encoded: "aGVsbG8gd29ybGQ=")!
print(data.hexString)
4 个解决方案
#1
114
An alternative implementation (taken from How to crypt string to sha1 with Swift?, with an additional option for uppercase output) would be
另一种实现(从如何使用Swift将crypt字符串转换为sha1 ?),对于大写输出,有一个附加的选项。
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 map { String(format: format, $0) }.joined()
}
}
I chose a hexEncodedString(options:)
method in the style of the existing method base64EncodedString(options:)
.
我以现有方法base64EncodedString(选项:)的样式选择了一个hexEncodedString(选项:)方法。
Data
conforms to the Collection
protocol, therefore one can use map()
to map each byte to the corresponding hex string. The %02x
format prints the argument in base 16, filled up to two digits with a leading zero if necessary. The hh
modifier causes the argument (which is passed as an integer on the stack) to be treated as a one byte quantity. One could omit the modifier here because $0
is an unsigned number (UInt8
) and no sign-extension will occur, but it does no harm leaving it in.
数据符合收集协议,因此可以使用map()将每个字节映射到相应的十六进制字符串。%02x格式打印以16为基数的参数,如果有必要,最多填充两位数的前导0。hh修饰符将使参数(在堆栈上作为整数传递)被视为一个字节量。在这里可以省略修饰符,因为$0是一个未签名的数字(UInt8),并且不会发生符号扩展,但是它不会造成伤害。
The result is then joined to a single string.
然后将结果连接到单个字符串。
Example:
例子:
let data = Data(bytes: [0, 1, 127, 128, 255])
print(data.hexEncodedString()) // 00017f80ff
print(data.hexEncodedString(options: .upperCase)) // 00017F80FF
The following implementation is faster by a factor about 120 (tested with 1000 random bytes). It is similar to RenniePet's solution and Nick Moore's solution, but based on UTF-16 code units, which is what Swift strings (currently) use as internal storage.
下面的实现速度快了大约120倍(使用1000个随机字节进行测试)。它类似于RenniePet的解决方案和Nick Moore的解决方案,但是基于UTF-16代码单元,这是Swift string(当前)使用的内部存储。
extension Data {
struct HexEncodingOptions: OptionSet {
let rawValue: Int
static let upperCase = HexEncodingOptions(rawValue: 1 << 0)
}
func hexEncodedString(options: HexEncodingOptions = []) -> String {
let hexDigits = Array((options.contains(.upperCase) ? "0123456789ABCDEF" : "0123456789abcdef").utf16)
var chars: [unichar] = []
chars.reserveCapacity(2 * count)
for byte in self {
chars.append(hexDigits[Int(byte / 16)])
chars.append(hexDigits[Int(byte % 16)])
}
return String(utf16CodeUnits: chars, count: chars.count)
}
}
#2
6
My version. It's not as elegant, but it's about 10 times faster than the accepted answer by Martin R.
我的版本。它不那么优雅,但比马丁·R的公认答案快了10倍。
extension Data {
private static let hexAlphabet = "0123456789abcdef".unicodeScalars.map { $0 }
public func hexEncodedString() -> String {
return String(self.reduce(into: "".unicodeScalars, { (result, value) in
result.append(Data.hexAlphabet[Int(value/16)])
result.append(Data.hexAlphabet[Int(value%16)])
}))
}
}
#3
5
This doesn't really answer the OP's question since it works on a Swift byte array, not a Data object. And it's much bigger than the other answers. But it should be more efficient since it avoids using String(format: ).
这并不能真正回答OP的问题,因为它在一个Swift字节数组上工作,而不是数据对象。它比其他答案要大得多。但是它应该更有效,因为它避免使用String(format:)。
Anyway, in the hopes someone finds this useful ...
不管怎么说,希望有人能发现这个有用的东西……
public class StringMisc {
// MARK: - Constants
// This is used by the byteArrayToHexString() method
private static let CHexLookup : [Character] =
[ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" ]
// Mark: - Public methods
/// Method to convert a byte array into a string containing hex characters, without any
/// additional formatting.
public static func byteArrayToHexString(_ byteArray : [UInt8]) -> String {
var stringToReturn = ""
for oneByte in byteArray {
let asInt = Int(oneByte)
stringToReturn.append(StringMisc.CHexLookup[asInt >> 4])
stringToReturn.append(StringMisc.CHexLookup[asInt & 0x0f])
}
return stringToReturn
}
}
Test case:
测试用例:
// Test the byteArrayToHexString() method
let byteArray : [UInt8] = [ 0x25, 0x99, 0xf3 ]
assert(StringMisc.byteArrayToHexString(byteArray) == "2599F3")
#4
5
This code extends the Data
type with a computed property. It iterates through the bytes of data and concatenates the byte's hex representation to the result:
此代码使用计算属性扩展数据类型。它遍历数据的字节并将字节的十六进制表示连接到结果:
extension Data {
var hexDescription: String {
return reduce("") {$0 + String(format: "%02x", $1)}
}
}
#1
114
An alternative implementation (taken from How to crypt string to sha1 with Swift?, with an additional option for uppercase output) would be
另一种实现(从如何使用Swift将crypt字符串转换为sha1 ?),对于大写输出,有一个附加的选项。
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 map { String(format: format, $0) }.joined()
}
}
I chose a hexEncodedString(options:)
method in the style of the existing method base64EncodedString(options:)
.
我以现有方法base64EncodedString(选项:)的样式选择了一个hexEncodedString(选项:)方法。
Data
conforms to the Collection
protocol, therefore one can use map()
to map each byte to the corresponding hex string. The %02x
format prints the argument in base 16, filled up to two digits with a leading zero if necessary. The hh
modifier causes the argument (which is passed as an integer on the stack) to be treated as a one byte quantity. One could omit the modifier here because $0
is an unsigned number (UInt8
) and no sign-extension will occur, but it does no harm leaving it in.
数据符合收集协议,因此可以使用map()将每个字节映射到相应的十六进制字符串。%02x格式打印以16为基数的参数,如果有必要,最多填充两位数的前导0。hh修饰符将使参数(在堆栈上作为整数传递)被视为一个字节量。在这里可以省略修饰符,因为$0是一个未签名的数字(UInt8),并且不会发生符号扩展,但是它不会造成伤害。
The result is then joined to a single string.
然后将结果连接到单个字符串。
Example:
例子:
let data = Data(bytes: [0, 1, 127, 128, 255])
print(data.hexEncodedString()) // 00017f80ff
print(data.hexEncodedString(options: .upperCase)) // 00017F80FF
The following implementation is faster by a factor about 120 (tested with 1000 random bytes). It is similar to RenniePet's solution and Nick Moore's solution, but based on UTF-16 code units, which is what Swift strings (currently) use as internal storage.
下面的实现速度快了大约120倍(使用1000个随机字节进行测试)。它类似于RenniePet的解决方案和Nick Moore的解决方案,但是基于UTF-16代码单元,这是Swift string(当前)使用的内部存储。
extension Data {
struct HexEncodingOptions: OptionSet {
let rawValue: Int
static let upperCase = HexEncodingOptions(rawValue: 1 << 0)
}
func hexEncodedString(options: HexEncodingOptions = []) -> String {
let hexDigits = Array((options.contains(.upperCase) ? "0123456789ABCDEF" : "0123456789abcdef").utf16)
var chars: [unichar] = []
chars.reserveCapacity(2 * count)
for byte in self {
chars.append(hexDigits[Int(byte / 16)])
chars.append(hexDigits[Int(byte % 16)])
}
return String(utf16CodeUnits: chars, count: chars.count)
}
}
#2
6
My version. It's not as elegant, but it's about 10 times faster than the accepted answer by Martin R.
我的版本。它不那么优雅,但比马丁·R的公认答案快了10倍。
extension Data {
private static let hexAlphabet = "0123456789abcdef".unicodeScalars.map { $0 }
public func hexEncodedString() -> String {
return String(self.reduce(into: "".unicodeScalars, { (result, value) in
result.append(Data.hexAlphabet[Int(value/16)])
result.append(Data.hexAlphabet[Int(value%16)])
}))
}
}
#3
5
This doesn't really answer the OP's question since it works on a Swift byte array, not a Data object. And it's much bigger than the other answers. But it should be more efficient since it avoids using String(format: ).
这并不能真正回答OP的问题,因为它在一个Swift字节数组上工作,而不是数据对象。它比其他答案要大得多。但是它应该更有效,因为它避免使用String(format:)。
Anyway, in the hopes someone finds this useful ...
不管怎么说,希望有人能发现这个有用的东西……
public class StringMisc {
// MARK: - Constants
// This is used by the byteArrayToHexString() method
private static let CHexLookup : [Character] =
[ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" ]
// Mark: - Public methods
/// Method to convert a byte array into a string containing hex characters, without any
/// additional formatting.
public static func byteArrayToHexString(_ byteArray : [UInt8]) -> String {
var stringToReturn = ""
for oneByte in byteArray {
let asInt = Int(oneByte)
stringToReturn.append(StringMisc.CHexLookup[asInt >> 4])
stringToReturn.append(StringMisc.CHexLookup[asInt & 0x0f])
}
return stringToReturn
}
}
Test case:
测试用例:
// Test the byteArrayToHexString() method
let byteArray : [UInt8] = [ 0x25, 0x99, 0xf3 ]
assert(StringMisc.byteArrayToHexString(byteArray) == "2599F3")
#4
5
This code extends the Data
type with a computed property. It iterates through the bytes of data and concatenates the byte's hex representation to the result:
此代码使用计算属性扩展数据类型。它遍历数据的字节并将字节的十六进制表示连接到结果:
extension Data {
var hexDescription: String {
return reduce("") {$0 + String(format: "%02x", $1)}
}
}