我有用户已经输入的字符数组。我想从所有字母数字字符、标点字符和符号的组合列表中获取用户尚未输入的随机字符。我已经浏览了文档,但找不到从字符集中获取随机元素的方法,这看起来很奇怪......我觉得我错过了一些明显的东西。
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() <- ???
}
Run Code Online (Sandbox Code Playgroud)
字符集不是集合。它是一个集合代数。
\n尽管它的名字是“a of”,但它并不是“a Setof Characters”。它是数学意义上的 UnicodeScalar(而非字符)的“集合”:定义是否包含给定 UnicodeScalar 的规则列表。没有直接的方法来枚举这些值。由于 UnicodeScalar 超出了有限范围,因此生成完整列表的方法效率较低,但它非常庞大。
不过我很好奇你会如何使用它。这可能包括许多您不期望的字符,例如 UNDERTIE (\xe2\x80\xbf)、SAMARITAN PUNCTUATION BAU (\xe0\xa0\xb3) 和 THAI CHARACTER FONGMAN (\xe0\xb9\x8f)。您真的想从所有 Unicode 字母数字和标点符号中选择一个随机值吗?(例如,有超过 800 个标点符号,据我粗略统计,可能有 25k 个字母数字。我还没有计算符号,但符号有很多。您在美式键盘上得到一个字符的机会是非常接近于零。)
\n我希望这是您真正寻找的代码:
\nlet asciiRange = 33...126\nlet randomCharacter = asciiRange.randomElement()\n .flatMap(UnicodeScalar.init)\n .flatMap(Character.init)!\nRun Code Online (Sandbox Code Playgroud)\n这将返回一个随机的、可打印的 ASCII 字符。
\n鉴于您的集合在 Unicode 空间中所占比例如此之大,以下是您如何快速获得真正随机的集合:
\nfunc randomCharacter() -> Character {\n // Drops the control characters and SPACE, the private use areas, tags, and the variation selectors.\n // The full range is 0x00...0x10FFFD\n let unicodeRange = 0x21...0x2FA1D\n let validCharacters: CharacterSet = .alphanumerics.union(.punctuationCharacters).union(.symbols)\n\n repeat {\n if let c = unicodeRange.randomElement().flatMap(UnicodeScalar.init),\n validCharacters.contains(c) {\n return Character(c)\n }\n } while true\n}\nRun Code Online (Sandbox Code Playgroud)\n我只是不断猜测,直到找到为止。只要您从中选择的集合与整个集合的大小相似,这就会趋于收敛。这可能比Set<Character>通过在类似的空间中行走来生成大量数据更有效。