Swift 如何从 CharacterSet 中获取随机元素
How to get random element from CharacterSet in Swift
我有一组用户已经输入的字符。我想从所有字母数字字符、标点字符和符号的组合列表中获取用户尚未输入的随机字符。我查看了文档,但找不到从 CharacterSet 中获取随机元素的方法,这看起来很奇怪......我觉得我遗漏了一些明显的东西。
func newRandomCharacter() -> Character {
let validCharacters: CharacterSet = .alphanumerics.union(.punctuationCharacters).union(.symbols)
var setOfUsedCharacters = CharacterSet()
// usedCharacters: [Character]
usedCharacters.forEach { setOfUsedCharacters.insert(charactersIn: String([=11=])) }
let setOfUnusedCharacters = validCharacters.subtracting(setOfUsedCharacters)
return setOfUnusedCharacters.randomElement() <- ???
}
字符集不是集合。它是一个 SetAlgebra。
尽管它的名字是“Characters
的 Set
”。它是数学意义上的一组 UnicodeScalar(不是字符):定义是否包含给定 UnicodeScalar 的规则列表。没有直接的方法来枚举这些值。由于 UnicodeScalar 在有限范围内,因此生成完整列表的方法效率低下,但它非常庞大。
不过,我很好奇您将如何使用它。这可能包括许多您意想不到的字符,例如 UNDERTIE (‿)、SAMARITAN PUNCTUATION BAU (࠳) 和 THAI CHARACTER FONGMAN (๏)。你真的想从所有 Unicode 字母数字和标点符号中挑选一个随机值吗? (例如,有超过 800 个标点字符,根据我的粗略计算,可能有 25k 个字母数字。我还没有计算符号,但有很多。你在美国键盘上得到一个字符的机会是非常接近于零。)
我想这就是您真正要找的代码:
let asciiRange = 33...126
let randomCharacter = asciiRange.randomElement()
.flatMap(UnicodeScalar.init)
.flatMap(Character.init)!
这将 return 一个随机的、可打印的 ASCII 字符。
鉴于您的集合占 Unicode 的很大一部分 space,以下是您如何相当快地获得真正随机的集合:
func randomCharacter() -> Character {
// Drops the control characters and SPACE, the private use areas, tags, and the variation selectors.
// The full range is 0x00...0x10FFFD
let unicodeRange = 0x21...0x2FA1D
let validCharacters: CharacterSet = .alphanumerics.union(.punctuationCharacters).union(.symbols)
repeat {
if let c = unicodeRange.randomElement().flatMap(UnicodeScalar.init),
validCharacters.contains(c) {
return Character(c)
}
} while true
}
我一直在猜,直到找到一个。只要您从中挑选的集合与完整集合的大小相似,这就会趋于收敛。这可能比通过走类似的 space.
生成巨大的 Set<Character>
更有效
我有一组用户已经输入的字符。我想从所有字母数字字符、标点字符和符号的组合列表中获取用户尚未输入的随机字符。我查看了文档,但找不到从 CharacterSet 中获取随机元素的方法,这看起来很奇怪......我觉得我遗漏了一些明显的东西。
func newRandomCharacter() -> Character {
let validCharacters: CharacterSet = .alphanumerics.union(.punctuationCharacters).union(.symbols)
var setOfUsedCharacters = CharacterSet()
// usedCharacters: [Character]
usedCharacters.forEach { setOfUsedCharacters.insert(charactersIn: String([=11=])) }
let setOfUnusedCharacters = validCharacters.subtracting(setOfUsedCharacters)
return setOfUnusedCharacters.randomElement() <- ???
}
字符集不是集合。它是一个 SetAlgebra。
尽管它的名字是“Characters
的 Set
”。它是数学意义上的一组 UnicodeScalar(不是字符):定义是否包含给定 UnicodeScalar 的规则列表。没有直接的方法来枚举这些值。由于 UnicodeScalar 在有限范围内,因此生成完整列表的方法效率低下,但它非常庞大。
不过,我很好奇您将如何使用它。这可能包括许多您意想不到的字符,例如 UNDERTIE (‿)、SAMARITAN PUNCTUATION BAU (࠳) 和 THAI CHARACTER FONGMAN (๏)。你真的想从所有 Unicode 字母数字和标点符号中挑选一个随机值吗? (例如,有超过 800 个标点字符,根据我的粗略计算,可能有 25k 个字母数字。我还没有计算符号,但有很多。你在美国键盘上得到一个字符的机会是非常接近于零。)
我想这就是您真正要找的代码:
let asciiRange = 33...126
let randomCharacter = asciiRange.randomElement()
.flatMap(UnicodeScalar.init)
.flatMap(Character.init)!
这将 return 一个随机的、可打印的 ASCII 字符。
鉴于您的集合占 Unicode 的很大一部分 space,以下是您如何相当快地获得真正随机的集合:
func randomCharacter() -> Character {
// Drops the control characters and SPACE, the private use areas, tags, and the variation selectors.
// The full range is 0x00...0x10FFFD
let unicodeRange = 0x21...0x2FA1D
let validCharacters: CharacterSet = .alphanumerics.union(.punctuationCharacters).union(.symbols)
repeat {
if let c = unicodeRange.randomElement().flatMap(UnicodeScalar.init),
validCharacters.contains(c) {
return Character(c)
}
} while true
}
我一直在猜,直到找到一个。只要您从中挑选的集合与完整集合的大小相似,这就会趋于收敛。这可能比通过走类似的 space.
生成巨大的Set<Character>
更有效