3

I have an array of UInt32 values. I would like to convert this array to a String.

This doesn't work:

let myUInt32Array: [UInt32] = [72, 101, 108, 108, 111, 128049]
let myString = String(myUInt32Array) // error
let myString = String(stringInterpolationSegment: myUInt32Array) // [72, 101, 108, 108, 111, 128049] (not what I want)

These SO posts show UTF8 and UTF16:

2 Answers 2

4

UnicodeScalar is a type alias for UInt32. So cast your UInt32 values to UnicodeScalar and then append them to a String.

let myUInt32Array: [UInt32] = [72, 101, 108, 108, 111, 128049]

var myString: String = ""

for value in myUInt32Array {
    if let scalar = UnicodeScalar(value) {
        myString.append(Character(scalar))
    }
}

print(myString) // Hello🐱
Sign up to request clarification or add additional context in comments.

1 Comment

@jvarela, updated. Thanks for the notice. In addition to converting to Character first, the UInt32 value must also be checked for nil.
3

(The answer has been updated for Swift 4 and later.)

Using the Swift type Data and String this can be done as

let myUInt32Array: [UInt32] = [72, 101, 108, 108, 111, 128049, 127465, 127466]
let data = Data(bytes: myUInt32Array, count: myUInt32Array.count * MemoryLayout<UInt32>.stride)
let myString = String(data: data, encoding: .utf32LittleEndian)!
print(myString) // Hello🐱🇩🇪

A forced unwrap is used here because a conversion from UTF-32 code points to a string cannot fail.

You can define a String extension for your convenience

extension String {
    init(utf32chars:[UInt32]) {
        let data = Data(bytes: utf32chars, count: utf32chars.count * MemoryLayout<UInt32>.stride)
        self = String(data: data, encoding: .utf32LittleEndian)!
    }
}

and use it as

let myUInt32Array: [UInt32] = [72, 101, 108, 108, 111, 128049, 127465, 127466]
let myString = String(utf32chars: myUInt32Array)
print(myString) // Hello🐱🇩🇪

And just for completeness, the generic converter from https://stackoverflow.com/a/24757284/1187415

extension String {
    init?<C : UnicodeCodec>(codeUnits:[C.CodeUnit], codec : C) {
        var codec = codec
        var str = ""
        var generator = codeUnits.makeIterator()
        var done = false
        while !done {
            let r = codec.decode(&generator)
            switch (r) {
            case .emptyInput:
                done = true
            case .scalarValue(let val):
                str.unicodeScalars.append(val)
            case .error:
                return nil
            }
        }
        self = str
    }
}

can be used with UTF-8, UTF-16 and UTF-32 input. In your case it would be

let myUInt32Array: [UInt32] = [72, 101, 108, 108, 111, 128049, 127465, 127466]
let myString = String(codeUnits: myUInt32Array, codec : UTF32())!
print(myString) // Hello🐱🇩🇪

4 Comments

Thank you for your answer. I have a few followup questions. (1) When should I choose to use the Foundation classes as opposed to the answer I gave? (2) I've read and understand a little about big endian and little endian byte order. But what is the reasoning behind using NSUTF32LittleEndianStringEncoding in your answer? Do I need to change anything when saving strings to a file or sending them over the network? If I just use the Swift classes can I avoid worrying about big/little endian encoding?
@Suragch: 1) I don't think there is a clear advantage of one over the other. I have shown the NSData/NSString method as an alternative because it is a little less code, but your method works as well. (That's also why I find your bounty question difficult to answer: All those methods work, so you can choose what you feel most familiar with.)
@Suragch: 2) All current OS X and iOS devices use little-endian for storing integer numbers in memory, therefore NSUTF32LittleEndianStringEncoding. Of course, if you sent data over the network to some different device with a possibly different byte order then you have to take care of that. But that is valid generally, and unrelated to your current question.
@l--marcl: I have updated the code for the current Swift.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.