I would like to separate a CamelCase string into space-separated words in a new string. Here is what I have so far:
var camelCaps: String {
guard self.count > 0 else { return self }
var newString: String = ""
let uppercase = CharacterSet.uppercaseLetters
let first = self.unicodeScalars.first!
newString.append(Character(first))
for scalar in self.unicodeScalars.dropFirst() {
if uppercase.contains(scalar) {
newString.append(" ")
}
let character = Character(scalar)
newString.append(character)
}
return newString
}
let aCamelCaps = "aCamelCaps"
let camelCapped = aCamelCaps.camelCaps // Produce: "a Camel Caps"
let anotherCamelCaps = "ÄnotherCamelCaps"
let anotherCamelCapped = anotherCamelCaps.camelCaps // "Änother Camel Caps"
I'm inclined to suspect that this may not be the most efficient way to convert to space-separated words, if I call it in a tight loop, or 1000's of times. Are there more efficient ways to do this in Swift?
[Edit 1:] The solution I require should remain general for Unicode scalars, not specific to Roman ASCII "A..Z".
[Edit 2:] The solution should also skip the first letter, i.e. not prepend a space before the first letter.
[Edit 3:] Updated for Swift 4 syntax, and added caching of uppercaseLetters, which improves performance in very long strings and tight loops.
Here another method to do the same thing for Swift 2.x
extension String {
func camelCaseToWords() -> String {
return unicodeScalars.reduce("") {
if NSCharacterSet.uppercaseLetterCharacterSet().characterIsMember(uint_least16_t($1.value)) {
return ($0 + " " + String($1))
}
else {
return ($0 + String($1))
}
}
}
}
Swift 3.x
extension String {
func camelCaseToWords() -> String {
return unicodeScalars.reduce("") {
if CharacterSet.uppercaseLetters.contains($1) {
return ($0 + " " + String($1))
}
else {
return $0 + String($1)
}
}
}
}
May be helpful for someone :)