In our code, we found a bug from not writing the alphabet correctly. Instead of "0123456789abcdefghijklmnopqrstuvwxyz"
, we had "0123456789abcdefghijklmnoqprstuvwxyz"
. So we are wondering if it's possible to avoid similar typo by declaring Strings made from ranges of characters?
Using Swift 4.1+, we tried:
let 📚1: String = "0"..."9" + "a"..."z"
Adjacent operators are in non-associative precedence group 'RangeFormationPrecedence'
let 📚2: String = ("0"..."9") + ("a"..."z")
Binary operator '+' cannot be applied to two '
ClosedRange<String>
' operands
let 📚3: String = String("0"..."9") + String("a"..."z")
Cannot invoke initializer for type 'String' with an argument list of type '
(ClosedRange<String>)
'
let 📚4: String = (Character("0")...Character("9")) + (Character("a")...Character("z"))
Binary operator '+' cannot be applied to two '
ClosedRange<Character>
' operands
let 📚5: String = String(Character("0")...Character("9")) + String(Character("a")...Character("z"))
Cannot invoke initializer for type 'String' with an argument list of type '
(ClosedRange<Character>)
'
"a"..."z"
is a ClosedRange
, but not a CountableClosedRange
.
It represents all strings s
for which "a" <= s <= "z"
according to the Unicode standard. That are not just the 26 lowercase letters from the english alphabet but many more, such as "ä", "è", "ô".
(Compare also
ClosedInterval<String> to [String] in Swift.)
In particular, "a"..."z"
is not a Sequence
, and that is why
String("a"..."z")
does not work.
What you can do is to create ranges of Unicode scalar values
which are (UInt32
) numbers (using the UInt32(_ v: Unicode.Scalar)
initializer):
let letters = UInt32("a") ... UInt32("z")
let digits = UInt32("0") ... UInt32("9")
and then create a string with all Unicode scalar values in those (countable!) ranges:
let string = String(String.UnicodeScalarView(letters.compactMap(UnicodeScalar.init)))
+ String(String.UnicodeScalarView(digits.compactMap(UnicodeScalar.init)))
print(string) // abcdefghijklmnopqrstuvwxyz0123456789
(For Swift before 4.1, replace compactMap
by flatMap
.)
This works also for non-ASCII characters. Example:
let greekLetters = UInt32("α") ... UInt32("ω")
let greekAlphabet = String(String.UnicodeScalarView(greekLetters.compactMap(UnicodeScalar.init)))
print(greekAlphabet) // αβγδεζηθικλμνξοπρςστυφχψω