7

I've got an array of Characters in swift:

static let charArray: [Character] = [ "S", "t", "r", "i", "n", "g"]

And I'd like to do some bitwise operations on each Character as a byte (UInt8). How do I convert charArray[0] to UInt8, for example?

JBaczuk
  • 13,886
  • 10
  • 58
  • 86
  • UInt8 is just 8 bits. That won't hold most characters. Limiting to US-ASCII is fine for your usecase? – Thilo Mar 15 '16 at 23:52
  • 1
    @Leo Dabus this isn't a duplicate because I'm trying to convert a Character not a string. – JBaczuk Mar 15 '16 at 23:54
  • @Thilo Yeah it's fine, just letters of the alphabet. – JBaczuk Mar 15 '16 at 23:54
  • String is just a sequence of characters.I can reopen it if you would like to – Leo Dabus Mar 15 '16 at 23:54
  • 1
    More appropriate duplicate: http://stackoverflow.com/questions/24102044/how-can-i-get-the-unicode-code-points-of-a-character – Thilo Mar 15 '16 at 23:55
  • @Leo Dabus It's up to you, but I guess the only way anyone knows so far is to convert it to a string anyway. Maybe a better answer will come around. – JBaczuk Mar 15 '16 at 23:55
  • @Thilo that is closer, but doesn't convert to a UInt8 – JBaczuk Mar 15 '16 at 23:58
  • That's just because it won't fit into a UInt8 for most characters. But you can convert to codepoint and see if it is small enough. – Thilo Mar 16 '16 at 00:00
  • Well I guess its a question of use case at this point, whether you need it as a UInt8. I'm trying to convert some Objective C to Swift. Thanks – JBaczuk Mar 16 '16 at 00:01
  • @JBaczuk you might take a look at this one also http://stackoverflow.com/a/34079948/2303865 – Leo Dabus Mar 16 '16 at 00:08

5 Answers5

17

You will need to go via the String representation of the Character:s to convert to UInt8. You needn't, however, explicitly initialize an array in your [Character] -> [UInt8] conversion; since String.UTF8View (from String.utf8) is a CollectionType, you can apply a map operation on the String.UTF8View itself; with an UInt8 initialization. I.e.,

let charArray: [Character] = [ "S", "t", "r", "i", "n", "g"]
let asUInt8Array = String(charArray).utf8.map{ UInt8($0) }

print(asUInt8Array)
/* [83, 116, 114, 105, 110, 103] */

print(asUInt8Array.dynamicType)
/* Array<UInt8> */

With regard to your comment below ("frustrated over the abstraction of Swift, as compared to the simple ways of Objective-C"): if you believe the above to be messy, you could include it in an extension to SequenceType constrained to Character elements, allowing easier use in practice. E.g.:

extension SequenceType where Generator.Element == Character {

    /* extension accessible as function */
    func asByteArray() -> [UInt8] {
        return String(self).utf8.map{UInt8($0)}
    }

    /* or, as @LeoDabus pointed out below (thanks!),
       use a computed property for this simple case  */
    var byteArray : [UInt8] {
        return String(self).utf8.map{UInt8($0)}
    }
}

Usage example:

let charArray: [Character] = [ "S", "t", "r", "i", "n", "g"]

/* use extension function */
let asUInt8Array = charArray.asByteArray()

/* or computed property */
let asUInt8Array = charArray.byteArray
dfrib
  • 70,367
  • 12
  • 127
  • 192
  • This is frustrating how abstracted Swift is. This is very simple in Objective-C. – JBaczuk Mar 16 '16 at 14:38
  • @JBaczuk I'm not well-versed with Obj-C, but generally, as a language focuses on "being safe", some "limitations" will end up making its way into the language, as compared to a less safe but _possibly_ (in some cases) more versatile language, w.r.t. somewhat low-level operations. However, with Swifts versatility of allowing extensions to native types, you can easily create your own wrappers to simplify what you consider non-simple code. As an example, I'll add a version of the solution above using an extension to `SequenceType` with `Generator.Element`:s constrained to `Character` type. – dfrib Mar 16 '16 at 16:06
  • That would make it more simple sure, good answer just frustrated with Swift, that's all. It's only "swift" for certain things. – JBaczuk Mar 16 '16 at 16:12
  • @dfri when extending any method if all you need to pass to that method is the element itself you can use a computed property ex. `var bytesArray: [UInt8] { return ... }` – Leo Dabus Mar 17 '16 at 20:06
  • 1
    @LeoDabus You're right, since we're not doing any throwing or such, a computed property would be more suitable above, thanks! (Will include in answer when not on a mobile device). – dfrib Mar 17 '16 at 21:02
4

I'm not sure how to convert a Character to UTF-8, but a String has a utf8 property, so you could use the following:

let charArray: [Character] = [ "S", "t", "r", "i", "n", "g"]
let string = Array(String(charArray).utf8)
print(string)
Michael
  • 8,891
  • 3
  • 29
  • 42
2

This is how I ended up doing it:

var char: Character = "a"
var byte: UInt8 = Array(String(char).utf8)[0]

There must be a better way...

JBaczuk
  • 13,886
  • 10
  • 58
  • 86
1

Swift 5:

let charArray: [Character] = [ "S", "t", "r", "i", "n", "g"]

var oneAscii: UInt8 = charArray[0].asciiValue!

Of course, if your input isn't a literal from the ASCII set, you want to be making sure the result isn't nil.

Hack Saw
  • 2,741
  • 1
  • 18
  • 33
  • 1
    This is risky, as the forced unwrap can cause the app to crash, especially if the source of the characters is developers control. – Cristik Nov 04 '21 at 01:36
  • True, I'm just showing a simple example of the solution, not the carefully checked version I'd actually use. In my case, I'm using a literal, so I know it works. If the input range could fail, one needs to check things... I'll add a warning. – Hack Saw Nov 04 '21 at 18:53
0

To improve @dfri answer https://stackoverflow.com/a/36025104/1979882

for Swift 3 you have to use this:

extension Sequence where Iterator.Element == Character {

    /* extension accessible as function */
    func asByteArray() -> [UInt8] {
        return String(self).utf8.map{UInt8($0)}
    }

    /* or, as @LeoDabus pointed out below (thanks!),
     use a computed property for this simple case  */
    var byteArray : [UInt8] {
        return String(self).utf8.map{UInt8($0)}
    }
}
Community
  • 1
  • 1
Vyacheslav
  • 26,359
  • 19
  • 112
  • 194