I've slightly modified the solution, found in answers pointed out by @Larme and @vadian. Both answers end up with the same algorithm. All I wanted was to look at the contents of the set. Yes, it is not a common thing to want to.
It turns out that the only way to get all the elements of CharacterSet
is to loop through all possible unicode scalars and check if they belong to the set. Feels so strange to me in the word where we can switch between Set
s, Array
s and even Dictionaries
so easy.
The reason for modification is and attempt to speed up the function. My rough experiments show that using scalars is 30% faster even if we create a string in the end.
extension CharacterSet {
func allUnicodeScalars() -> [UnicodeScalar] {
var result: [UnicodeScalar] = []
for plane in Unicode.UTF8.CodeUnit.min...16 where self.hasMember(inPlane: plane) {
for unicode in Unicode.UTF32.CodeUnit(plane) << 16 ..< Unicode.UTF32.CodeUnit(plane + 1) << 16 {
if let uniChar = UnicodeScalar(unicode), self.contains(uniChar) {
result.append(uniChar)
}
}
}
return result
}
}
// Testing and timing
printTimeElapsedWhenRunningCode(title:"allUnicodeScalars()") {
print(String.UnicodeScalarView(chSet.allUnicodeScalars()))
}
// Time elapsed for allUnicodeScalars(): 1.936843991279602 s.
printTimeElapsedWhenRunningCode(title:"allCharacters()") {
print(String(chSet.allCharacters()))
}
// Time elapsed for allCharacters(): 2.9846099615097046 s.
//Timing functions (for reference):
private func printTimeElapsedWhenRunningCode(title:String, operation:()->()) {
let startTime = CFAbsoluteTimeGetCurrent()
operation()
let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
print("Time elapsed for \(title): \(timeElapsed) s.")
}
private func timeElapsedInSecondsWhenRunningCode(operation: ()->()) -> Double {
let startTime = CFAbsoluteTimeGetCurrent()
operation()
let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
return Double(timeElapsed)
}
UPD: Yes, the question is a duplicate, and a better answer exists.