Swift: generate an array of (Swift) characters

青春壹個敷衍的年華 提交于 2019-11-29 09:32:56

It's a little cumbersome to get the initial character code (i.e. 'a' in c / Obj-C) in Swift, but you can do it like this:

let aScalars = "a".unicodeScalars
let aCode = aScalars[aScalars.startIndex].value

let letters: [Character] = (0..<26).map {
    i in Character(UnicodeScalar(aCode + i))
}

Thanks for useful answers.

I'm using one-liner version.

let xs = (97...122).map({Character(UnicodeScalar($0))})

or

let xs = (0..<26).map({Character(UnicodeScalar("a".unicodeScalars.first!.value + $0))})

Xcode 10 • Swift 4.2

extension ClosedRange where Bound == Unicode.Scalar {
    static let asciiPrintable: ClosedRange = " "..."~"
    var range: ClosedRange<UInt32>  { return lowerBound.value...upperBound.value }
    var scalars: [Unicode.Scalar]   { return range.compactMap(Unicode.Scalar.init) }
    var characters: [Character]     { return scalars.map(Character.init) }
    var string: String              { return String(scalars) }
}

extension String {
    init<S: Sequence>(_ sequence: S) where S.Element == Unicode.Scalar {
        self.init(UnicodeScalarView(sequence))
    }
}

let characters = ("a"..."z").characters  // "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
let string = ("a"..."z").string          // "abcdefghijklmnopqrstuvwxyz"

let range = ClosedRange.asciiPrintable         // {lowerBound " ", upperBound "~"}   32...126
let characters = range.characters  // [" ", "!", """, "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~"]
let string = range.string          // " !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"

If you just want an array of a known set:

let str = "abcdefghijklmnopqrstuvwxyz"
let characterArray = Array(str)
println(characterArray)

//[a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z]

With Swift 5, you can use the following Playground sample code in order to get an array of characters from a range of Unicode scalars:

// 1.
let unicodeScalarRange: ClosedRange<Unicode.Scalar> = "A" ... "Z"
// 2.
let unicodeScalarValueRange: ClosedRange<UInt32> = unicodeScalarRange.lowerBound.value ... unicodeScalarRange.upperBound.value
// 3.
let unicodeScalarArray: [Unicode.Scalar] = unicodeScalarValueRange.compactMap(Unicode.Scalar.init)
// 4.
let characterArray: [Character] = unicodeScalarArray.map(Character.init)

print(characterArray)
/*
 prints: ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
 */
  1. Create a range of Unicode scalars that match the code points for uppercased latin alphabet Unicode block.
  2. Because this first range is not strideable (you can't iterate on it), convert it to a range of Unicode scalar numeric representations using Unicode.Scalar's value property.
  3. Iterate over your range of Unicode scalar numeric representations in order to create an array of Unicode scalars.
  4. Iterate over your array of Unicode scalars in order to create an array of characters.

As an alternative, you can use one of the sample codes below if you need to start from a range of Characters or a range of Strings:

let unicodeScalarRange: ClosedRange<Character> = "A" ... "Z"
let unicodeScalarValueRange = unicodeScalarRange.lowerBound.unicodeScalars[unicodeScalarRange.lowerBound.unicodeScalars.startIndex].value ... unicodeScalarRange.upperBound.unicodeScalars[unicodeScalarRange.lowerBound.unicodeScalars.startIndex].value
let unicodeScalarArray = unicodeScalarValueRange.compactMap(Unicode.Scalar.init)
let characterArray = unicodeScalarArray.map(Character.init)

print(characterArray)
/*
 prints: ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
 */
let unicodeScalarRange: ClosedRange<String> = "A" ... "Z"
let unicodeScalarValueRange = unicodeScalarRange.lowerBound.unicodeScalars[unicodeScalarRange.lowerBound.unicodeScalars.startIndex].value ... unicodeScalarRange.upperBound.unicodeScalars[unicodeScalarRange.lowerBound.unicodeScalars.startIndex].value
let unicodeScalarArray = unicodeScalarValueRange.compactMap(Unicode.Scalar.init)
let characterArray = unicodeScalarArray.map(Character.init)

print(characterArray)
/*
 prints: ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
 */

Details

  • Xcode Version 10.3 (10G8), Swift 5

Solution 1

// MAKR: - ClosedRange extensions

extension ClosedRange where Bound == Unicode.Scalar {
    var representationRange: ClosedRange<UInt32> { return lowerBound.value...upperBound.value }
    var scalars: [Bound] { return representationRange.compactMap(Bound.init) }
}

extension ClosedRange where Bound == Character {
    var scalars: [Unicode.Scalar]? {
        guard lowerBound.unicodeScalars.count == 1, upperBound.unicodeScalars.count == 1 else { return nil }
        return (lowerBound.unicodeScalars.first! ... upperBound.unicodeScalars.first!).scalars
    }
    var all: [Bound]? { return scalars?.map(Character.init) }
}

extension ClosedRange where Bound == String  {
    var scalars: [Unicode.Scalar]? {
        guard   lowerBound.unicodeScalars.count == 1, upperBound.unicodeScalars.count == 1,
                let first = lowerBound.first, let last = upperBound.first else { return nil }
        return (first...last).scalars
    }
    var all: [Bound]? { return scalars?.map(String.init) }
}

// MAKR: - Array extensions

extension Array where Element == Character {
    init?(_ range: ClosedRange<Element>) {
        guard let array = range.all else { return nil }
        self = array
    }
}

extension Array where Element == String {
    init?(_ range: ClosedRange<Element>) {
        guard let array = range.all else { return nil }
        self = array
    }
}

extension Array where Element == Unicode.Scalar { init(_ range: ClosedRange<Element>) { self = range.scalars } }

Usage 1

func test(value: Any) { print("-- \(type(of: value)) : \(value)") }

print("====================")
test(value: ("a"..."z").scalars ?? [])
test(value: ("a"..."z").all ?? [])
test(value: ("aa"..."z").all ?? [])
test(value: ("a"..."zz").all ?? [])
print("====================")
test(value: (Character("a")...Character("z")).scalars ?? [])
test(value: (Character("a")...Character("z")).all ?? [])
print("====================")
test(value: (Unicode.Scalar("a")...Unicode.Scalar("z")).scalars)
print("====================")
test(value: [Unicode.Scalar]("a"..."z"))
test(value: [Character]("a"..."z") ?? [])
test(value: [String]("a"..."z") ?? [])
test(value: [String]("aa"..."z") ?? [])
test(value: [String]("a"..."zz") ?? [])

Usage 1 log

====================
-- Array<Scalar> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
-- Array<String> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
-- Array<String> : []
-- Array<String> : []
====================
-- Array<Scalar> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
-- Array<Character> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
====================
-- Array<Scalar> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
====================
-- Array<Scalar> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
-- Array<Character> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
-- Array<String> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
-- Array<String> : []
-- Array<String> : []

Solution 2

extension Unicode.Scalar: Strideable {
    public typealias Stride = Int
    public func distance(to other: Unicode.Scalar) -> Stride { return abs(Int(value) - Int(other.value)) }
    public func advanced(by n: Stride) -> Unicode.Scalar { return Unicode.Scalar(value + UInt32(n)) ?? self }
}

extension Character: Strideable {
    public typealias Stride = Int
    public func distance(to other: Character) -> Stride {
        guard unicodeScalars.count == 1, other.unicodeScalars.count == 1 else { return 0 }
        return unicodeScalars.first!.distance(to: other.unicodeScalars.first!)
    }
    public func advanced(by n: Stride) -> Character {
        guard unicodeScalars.count == 1 else { return self }
        return Character(unicodeScalars.first!.advanced(by: n))
    }
}

extension Array where Element == String {
    init?(_ range: ClosedRange<Element>) {
        guard   range.lowerBound.unicodeScalars.count == 1, range.upperBound.unicodeScalars.count == 1,
                let first = range.lowerBound.unicodeScalars.first, let last = range.upperBound.unicodeScalars.first else { return nil }
        self = [Unicode.Scalar](first...last).map(String.init)
    }
}

Usage 2

func test(value: Any) { print("-- \(type(of: value)) : \(value)") }

test(value: [Unicode.Scalar]("a"..."z"))
test(value: [Character]("a"..."z"))
test(value: [String]("a"..."z"))
test(value: Array("a"..."z"))
test(value: Array(Character("a")...Character("z")))
test(value: Array(Unicode.Scalar("a")...Unicode.Scalar("z")))

Usage 2 log

-- Array<Scalar> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
-- Array<Character> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
-- Optional<Array<String>> : Optional(["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"])
-- Optional<Array<String>> : Optional(["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"])
-- Array<Character> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
-- Array<Scalar> : ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]

Solving for:

// trying to do something like this (pseudo code):
// let letters:[Character] = map(0..<26) { i in 'a' + i }

with Swift 4.2 / 5.0:

extension Character: Strideable {
    public typealias Stride = Int

    // https://stackoverflow.com/questions/39982335/creating-a-countableclosedrangecharacter
    public func distance(to other: Character) -> Character.Stride {
        let stride = Int(String(self).unicodeScalars.first!.value) - Int(String(other).unicodeScalars.first!.value)
        return abs(stride)
    }

    public func advanced(by n: Character.Stride) -> Character {
        return Character(UnicodeScalar(String(self).unicodeScalars.first!.value + UInt32(n))!)
    }
}

extension ClosedRange where Element == Character {

    var characters: [Character] { return Array(self) }
}

yields:

let letters: [Character] = ("A"..."Z").characters
print(letters)
// ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]

(11...36).map { String($0 - 1, radix: $0) }

You can simply use let alphabets: [UnicodeScalar] = Array("A"..."Z")

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!