在Swift中给定一个十六进制字符串,将其转换为十六进制值

4
假设我有这样一个字符串:
D7C17A4F
如何将每个单独的字符转换为十六进制值?
因此, D 应该是 0xD , 7 应该是 0x7 ……
现在,我把每个单独的字符表示为它的 ASCII 值。 D 是 68, 7 是 55 。 我正在尝试将这两个值打包成一个字节。例如: D7 变成了 0xD7 , C1 变成了 0xC1 。但是,我不能使用ASCII十进制值来完成这个操作。

2
你想要一个包含8个数字(13,7,...)的数组还是一个包含4个数字(0xD7,0xC1,...)的数组?这个字符串总是8个十六进制字符长,还是可能更长或更短? - Martin R
字符串始终为32个字符长。一个由4个数字组成的数组更好。不过两者都可以。 - Manning10118
但是一个由32个字符组成的字符串应该是16个数字吗? - Martin R
5个回答

5
一个可能的解决方案:
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)
}

使用https://stackoverflow.com/a/29306523/1187415提出的方法,将字符串分成两个字符的子字符串。每个子字符串被解释为16进制数字序列,并使用strtoul()转换为数字。

验证结果:

println(numbers)
// [215, 193, 122, 79]

println(map(numbers, { String(format: "%02X", $0) } ))
// [D7, C1, 7A, 4F]

针对 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) 

或者
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) 

第二种解决方案看起来有些复杂,但是它的小优点在于不需要额外的chars数组。

在Swift 2中,使用map函数对stride进行操作的方法去哪了?那看起来是一个优雅的解决方案。 - dwaz

1

这是基于 @Martin R的答案修改后的 Swift 3 版本。这个变体也可以接受长度为奇数的字符串。

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

0

使用代码块

"D7C17A4F"
  .chunks(ofCount: 2)
  .map { UInt8($0, radix: 0x10)! }

-1

我对@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
    }

}

-1

这里有一个更通用的、"纯Swift"的方法(不需要Foundation :-))

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]

对于SignedInteger来说,做同样的事情也非常容易,但更好的方法是将结果映射到有符号类型

let u8 = u1?.map { Int8(bitPattern: $0) }                    // [-14, 52, 95]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接