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{|}~"
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"]
*/
- Create a range of Unicode scalars that match the code points for uppercased latin alphabet Unicode block.
- 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
.
- Iterate over your range of Unicode scalar numeric representations in order to create an array of Unicode scalars.
- 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 Character
s or a range of String
s:
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"]