I have an array of characters the user has already entered. I would like to get a random character that the user has not already entered from a combined list of all of the alphanumeric characters, the punctuation characters and the symbols. I have looked through the documentation but can't find a way to get a random element from a CharacterSet, which seems odd... I feel like I am missing something obvious.
func newRandomCharacter() -> Character {
let validCharacters: CharacterSet = .alphanumerics.union(.punctuationCharacters).union(.symbols)
var setOfUsedCharacters = CharacterSet()
// usedCharacters: [Character]
usedCharacters.forEach { setOfUsedCharacters.insert(charactersIn: String($0)) }
let setOfUnusedCharacters = validCharacters.subtracting(setOfUsedCharacters)
return setOfUnusedCharacters.randomElement() <- ???
}
CodePudding user response:
Well, I guess is what you are missing is, questioning, what I wanna do and how to solve it:
I want to get a random characters out of a collection of characters.
Or:
I want to get a random index in the range of [0..X], where X must be the total number of character items in your "setOfUnusedCharacters" collection.
Ending up:
Calculate a random integer value that is in beetween zero and the total amount of characters
CodePudding user response:
A CharacterSet is not a Collection. It is a SetAlgebra.
It is not, despite its name, "a Set
of Characters
." It is a "set" of UnicodeScalars (not Characters) in the mathematical sense: a list of rules that define whether a given UnicodeScalar is contained. There is no direct way to enumerate the values. There are inefficient ways to generate a complete list since UnicodeScalar is over a finite range, but it's quite massive.
I'm curious how you would use this, though. This may include a lot of characters you're not expecting like UNDERTIE (‿), SAMARITAN PUNCTUATION BAU (࠳), and THAI CHARACTER FONGMAN (๏). Are you really looking to pick a random value out all Unicode alphanumerics and punctuation? (There are over 800 punctuation characters, for example, and by my rough count maybe 25k alphanumerics. I haven't counted symbols yet. The chance that you'll get a character on a US keyboard is pretty close to zero.)
I expect this is the code you're really looking for:
let asciiRange = 33...126
let randomCharacter = asciiRange.randomElement()
.flatMap(UnicodeScalar.init)
.flatMap(Character.init)!
This will return a random, printable ASCII character.