Suppose I am given a string like this:
假设我得到一个这样的字符串:
D7C17A4F
How do I convert each individual character to a hex value?
如何将每个字符转换为十六进制值?
So D
should be 0xD
, 7
should be 0x7
…
所以D应该是0xD,7应该是0x7 ......
Right now, I have each individual character represented as it's ASCII value. D
is 68
, 7
is 55
. I'm trying to pack those two values into one byte. For example: D7
becomes 0xD7
and C1
becomes 0xC1
. I can't do that using the ASCII decimal values though.
现在,我将每个单独的字符表示为ASCII值。 D是68,7是55.我试图将这两个值打包成一个字节。例如:D7变为0xD7,C1变为0xC1。我不能使用ASCII十进制值来做到这一点。
4 个解决方案
#1
A possible solution:
可能的解决方案:
let string = "D7C17A4F"
let chars = Array(string)
let numbers = map (stride(from: 0, to: chars.count, by: 2)) {
strtoul(String(chars[$0 ..< $0+2]), nil, 16)
}
Using the approach from https://*.com/a/29306523/1187415, the string is split into substrings of two characters. Each substring is interpreted as a sequence of digits in base 16, and converted to a number with strtoul()
.
使用https://*.com/a/29306523/1187415中的方法,字符串将拆分为两个字符的子字符串。每个子字符串被解释为基数16中的数字序列,并转换为带有strtoul()的数字。
Verify the result:
验证结果:
println(numbers)
// [215, 193, 122, 79]
println(map(numbers, { String(format: "%02X", $0) } ))
// [D7, C1, 7A, 4F]
Update for Swift 2 (Xcode 7):
更新Swift 2(Xcode 7):
let string = "D7C17A4F"
let chars = Array(string.characters)
let numbers = 0.stride(to: chars.count, by: 2).map {
UInt8(String(chars[$0 ..< $0+2]), radix: 16) ?? 0
}
print(numbers)
or
let string = "D7C17A4F"
var numbers = [UInt8]()
var from = string.startIndex
while from != string.endIndex {
let to = from.advancedBy(2, limit: string.endIndex)
numbers.append(UInt8(string[from ..< to], radix: 16) ?? 0)
from = to
}
print(numbers)
The second solution looks a bit more complicated but has the small advantage that no additional chars
array is needed.
第二种解决方案看起来有点复杂,但具有不需要额外的字符串阵列的小优势。
#2
Swift 3 version, modified from @Martin R's answer. This variant also accepts incoming string with odd length.
Swift 3版本,改编自@Martin R的答案。此变体还接受奇数长度的传入字符串。
let string = "D7C17A4F"
let chars = Array(string.characters)
let numbers = stride(from: 0, to: chars.count, by: 2).map() {
strtoul(String(chars[$0 ..< min($0 + 2, chars.count)]), nil, 16)
}
#3
My variation of @martin-r answer:
我对@ martin-r的变化回答:
extension String {
func hexToByteArray() -> [UInt8] {
let byteCount = self.utf8.count / 2
var array = [UInt8](count: byteCount, repeatedValue: 0)
var from = self.startIndex
for i in 0..<byteCount {
let to = from.successor()
let sub = self.substringWithRange(from...to)
array[i] = UInt8(sub, radix: 16) ?? 0
from = to.successor()
}
return array
}
}
#4
here is the more generic, "pure swift" approach (no Foundation required :-))
这里是更通用的,“纯粹的快速”方法(没有基金会要求:-))
extension UnsignedInteger {
var hex: String {
var str = String(self, radix: 16, uppercase: true)
while str.characters.count < 2 * MemoryLayout<Self>.size {
str.insert("0", at: str.startIndex)
}
return str
}
}
extension Array where Element: UnsignedInteger {
var hex: String {
var str = ""
self.forEach { (u) in
str.append(u.hex)
}
return str
}
}
let str = [UInt8(1),22,63,41].hex // "01163F29"
let str2 = [UInt(1),22,63,41].hex // "00000000000000010000000000000016000000000000003F0000000000000029"
extension String {
func toUnsignedInteger<T:UnsignedInteger>()->[T]? {
var ret = [T]()
let nibles = MemoryLayout<T>.size * 2
for i in stride(from: 0, to: characters.count, by: nibles) {
let start = self.index(startIndex, offsetBy: i)
guard let end = self.index(start, offsetBy: nibles, limitedBy: endIndex),
let ui = UIntMax(self[start..<end], radix: 16) else { return nil }
ret.append(T(ui))
}
return ret
}
}
let u0:[UInt8]? = str.toUnsignedInteger() // [1, 22, 63, 41]
let u1 = "F2345f".toUnsignedInteger() as [UInt8]? // [18, 52, 95]
let u2 = "12345f".toUnsignedInteger() as [UInt16]? // nil
let u3 = "12345g".toUnsignedInteger() as [UInt8]? // nil
let u4 = "12345f".toUnsignedInteger() as [UInt]? // nil
let u5 = "12345678".toUnsignedInteger() as [UInt8]? // [18, 52, 86, 120]
let u6 = "12345678".toUnsignedInteger() as [UInt16]? // [4660, 22136]
let u7 = "1234567812345678".toUnsignedInteger() as [UInt]? // [1311768465173141112]
It is very easily to do the same for SignedInteger as well, but better approach will be to map results to signed type
对于SignedInteger也很容易做同样的事情,但更好的方法是将结果映射到有符号类型
let u8 = u1?.map { Int8(bitPattern: $0) } // [-14, 52, 95]
#1
A possible solution:
可能的解决方案:
let string = "D7C17A4F"
let chars = Array(string)
let numbers = map (stride(from: 0, to: chars.count, by: 2)) {
strtoul(String(chars[$0 ..< $0+2]), nil, 16)
}
Using the approach from https://*.com/a/29306523/1187415, the string is split into substrings of two characters. Each substring is interpreted as a sequence of digits in base 16, and converted to a number with strtoul()
.
使用https://*.com/a/29306523/1187415中的方法,字符串将拆分为两个字符的子字符串。每个子字符串被解释为基数16中的数字序列,并转换为带有strtoul()的数字。
Verify the result:
验证结果:
println(numbers)
// [215, 193, 122, 79]
println(map(numbers, { String(format: "%02X", $0) } ))
// [D7, C1, 7A, 4F]
Update for Swift 2 (Xcode 7):
更新Swift 2(Xcode 7):
let string = "D7C17A4F"
let chars = Array(string.characters)
let numbers = 0.stride(to: chars.count, by: 2).map {
UInt8(String(chars[$0 ..< $0+2]), radix: 16) ?? 0
}
print(numbers)
or
let string = "D7C17A4F"
var numbers = [UInt8]()
var from = string.startIndex
while from != string.endIndex {
let to = from.advancedBy(2, limit: string.endIndex)
numbers.append(UInt8(string[from ..< to], radix: 16) ?? 0)
from = to
}
print(numbers)
The second solution looks a bit more complicated but has the small advantage that no additional chars
array is needed.
第二种解决方案看起来有点复杂,但具有不需要额外的字符串阵列的小优势。
#2
Swift 3 version, modified from @Martin R's answer. This variant also accepts incoming string with odd length.
Swift 3版本,改编自@Martin R的答案。此变体还接受奇数长度的传入字符串。
let string = "D7C17A4F"
let chars = Array(string.characters)
let numbers = stride(from: 0, to: chars.count, by: 2).map() {
strtoul(String(chars[$0 ..< min($0 + 2, chars.count)]), nil, 16)
}
#3
My variation of @martin-r answer:
我对@ martin-r的变化回答:
extension String {
func hexToByteArray() -> [UInt8] {
let byteCount = self.utf8.count / 2
var array = [UInt8](count: byteCount, repeatedValue: 0)
var from = self.startIndex
for i in 0..<byteCount {
let to = from.successor()
let sub = self.substringWithRange(from...to)
array[i] = UInt8(sub, radix: 16) ?? 0
from = to.successor()
}
return array
}
}
#4
here is the more generic, "pure swift" approach (no Foundation required :-))
这里是更通用的,“纯粹的快速”方法(没有基金会要求:-))
extension UnsignedInteger {
var hex: String {
var str = String(self, radix: 16, uppercase: true)
while str.characters.count < 2 * MemoryLayout<Self>.size {
str.insert("0", at: str.startIndex)
}
return str
}
}
extension Array where Element: UnsignedInteger {
var hex: String {
var str = ""
self.forEach { (u) in
str.append(u.hex)
}
return str
}
}
let str = [UInt8(1),22,63,41].hex // "01163F29"
let str2 = [UInt(1),22,63,41].hex // "00000000000000010000000000000016000000000000003F0000000000000029"
extension String {
func toUnsignedInteger<T:UnsignedInteger>()->[T]? {
var ret = [T]()
let nibles = MemoryLayout<T>.size * 2
for i in stride(from: 0, to: characters.count, by: nibles) {
let start = self.index(startIndex, offsetBy: i)
guard let end = self.index(start, offsetBy: nibles, limitedBy: endIndex),
let ui = UIntMax(self[start..<end], radix: 16) else { return nil }
ret.append(T(ui))
}
return ret
}
}
let u0:[UInt8]? = str.toUnsignedInteger() // [1, 22, 63, 41]
let u1 = "F2345f".toUnsignedInteger() as [UInt8]? // [18, 52, 95]
let u2 = "12345f".toUnsignedInteger() as [UInt16]? // nil
let u3 = "12345g".toUnsignedInteger() as [UInt8]? // nil
let u4 = "12345f".toUnsignedInteger() as [UInt]? // nil
let u5 = "12345678".toUnsignedInteger() as [UInt8]? // [18, 52, 86, 120]
let u6 = "12345678".toUnsignedInteger() as [UInt16]? // [4660, 22136]
let u7 = "1234567812345678".toUnsignedInteger() as [UInt]? // [1311768465173141112]
It is very easily to do the same for SignedInteger as well, but better approach will be to map results to signed type
对于SignedInteger也很容易做同样的事情,但更好的方法是将结果映射到有符号类型
let u8 = u1?.map { Int8(bitPattern: $0) } // [-14, 52, 95]