4

I have a data source that is passing me a hex string (such as 11C01) that I need to convert each character in it into an integer or byte value so that I can use it as a bit field (i.e. doing things like value | 0x01 == 0 like you would in old C-style bit fields). The language for this will be Swift.

For the life of me I cannot find a way to convert a character containing a hex value into an integer without doing some weird round-about putting into NSData then converting it from there or doing it using C in an Objective-C class. Just looking for something in Swift to do this instead of resorting to that.

A sample string would be this: 11C01 I need it to create an array of bytes or integers like this: 0x1, 0x1, 0xC, 0x0, 0x1.

The output should be an int or byte that I can do the bitwise operation on.

How would I go about doing this?

Thanks in advance!

Khirok
  • 517
  • 1
  • 13
  • 21

3 Answers3

14

edit/update:

Swift 5 or later you can use Character property hexDigitValue:

let hexaString = "11C01"

let integers = hexaString.compactMap(\.hexDigitValue)
let bytes = integers.map(UInt8.init)
let hexaArray = hexaString.map { "0x" + String($0) }

print(integers)  // "[1, 1, 12, 0, 1]"
print(bytes)  // "[1, 1, 12, 0, 1]"
print(hexaArray)  // "["0x1", "0x1", "0xC", "0x0", "0x1"]\n"

To convert every 2 characters into a byte (hexa to byte):

extension Collection {
    func unfoldSubSequences(limitedTo maxLength: Int) -> UnfoldSequence<SubSequence,Index> {
        sequence(state: startIndex) { start in
            guard start < self.endIndex else { return nil }
            let end = self.index(start, offsetBy: maxLength, limitedBy: self.endIndex) ?? self.endIndex
            defer { start = end }
            return self[start..<end]
        }
    }
}

extension StringProtocol {
    var byte: UInt8? { UInt8(self, radix: 16) }
    var hexaToBytes: [UInt8] { unfoldSubSequences(limitedTo: 2).compactMap(\.byte) }
    var hexaToData: Data { .init(hexaToBytes) }
}

"11C011".hexaToBytes  // [17, 192, 17]
"11C011".hexaToData  // 3 bytes
[0x11, 0xC0, 0x11]   // [17, 192, 17]
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • 1
    Worked perfectly! Thank you! Sorry for late reply on this been crazy busy. – Khirok Jan 26 '15 at 21:17
  • @LeoDabus i would like to ask, if instead of [1, 1, 12, 0, 1] i would want to trim in bytes example hexaString = "11C011" and resultArray = [11, C0, 11] how can i do that? – wes. i Mar 20 '16 at 04:42
  • 1
    Thank you very much! @LeoDabus – wes. i Mar 20 '16 at 12:08
  • I find the question confusing as it is not converting to bytes, but to nibbles. ie 4bit representation, not an 8bit representation. (The solution however does convert to bytes, but it's not using the ogrinal data ie 0x11C011 != 0x11C01 – maninvan Apr 01 '22 at 19:59
10
let int_value = UInt64("11c01", radix: 16)

Then can shift the bits out

NOTE: Make sure data type can hold value

Matt
  • 399
  • 3
  • 6
3

For the purposes of fun rather than clarity:

let hex_string = "11C01"

let result = hex_string.utf8.map() {
   $0 & 0xf + $0 >> 6 | ($0 & 0x40) >> 3
}
// result: UInt8 array: [1, 1, 12, 0, 1]
Joannes
  • 2,569
  • 3
  • 17
  • 39
Matt Gibson
  • 37,886
  • 9
  • 99
  • 128