Swift: создать массив символов (Swift)

Простой вопрос - надеюсь, я пытаюсь создать простой массив символов, что-то в духе:

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

и попробовали следующее безрезультатно

let a = Character("a")
let z = Character("z")
let r:Range<Character> = a..<z
let letters:[Character] = map(a..<z) { i in i }

Я понимаю, что Swift использует Unicode, каков правильный способ сделать что-то вроде этого?

(Обратите внимание, что это не вопрос о взаимодействии с устаревшим Obj-C char, строго в Swift для тестирования и т.д.).

Ответ 1

Немного громоздко получить исходный код символа (т.е. 'a' в c/Obj-C) в Swift, но вы можете сделать это следующим образом:

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

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

Ответ 2

Спасибо за полезные ответы.

Я использую однострочный вариант.

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

или

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

Ответ 3

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:;<=>[email protected][\\]^_'abcdefghijklmnopqrstuvwxyz{|}~"

Ответ 4

Если вам нужен массив известного набора:

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]

Ответ 5

В Swift 5 вы можете использовать следующий пример кода Playground, чтобы получить массив символов из ряда скаляров Unicode:

// 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. Создайте диапазон скаляров Unicode, которые соответствуют кодовым точкам для блока Unicode верхнего регистра латинского алфавита.
  2. Поскольку это первый диапазон не strideable (вы не можете перебирать на нем), преобразовать его в диапазоне Unicode скалярных числовых представлений, используя Unicode.Scalar value property.
  3. Выполните итерацию по вашему диапазону скалярных числовых представлений Unicode, чтобы создать массив скаляров Unicode.
  4. Выполните итерацию по вашему массиву скаляров Unicode, чтобы создать массив символов.

В качестве альтернативы вы можете использовать один из приведенных ниже примеров кодов, если вам нужно начать с диапазона Character или диапазона String:

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"]
 */

Ответ 6

Подробнее

  • Версия Xcode 10.3 (10G8), Swift 5

Решение 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 } }

Использование 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") ?? [])

Журнал использования 1

====================
-- 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> : []

Решение 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)
    }
}

Использование 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")))

Журнал использования 2

-- 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"]

Ответ 7

Решение для:

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

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

выходы:

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"]

Ответ 8

(11... 36).map {String ($ 0 - 1, основание: $ 0)}

Ответ 9

Вы можете просто использовать let alphabets: [UnicodeScalar] = Array("A"..."Z")