我想将一个CamelCase字符串分隔成一个新字符串中的空格分隔的单词。 这是我到目前为止:
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"我倾向于怀疑,如果我将它称为紧密循环或1000年的时间,这可能不是转换为空间分隔词的最有效方式。 在Swift中有更有效的方法吗?
[编辑1:]我需要的解决方案对Unicode标量应该保持通用,而不是特定于罗马ASCII“A..Z”。
[编辑2:]解决方案也应该跳过第一个字母,即不要在第一个字母前加一个空格。
[编辑3:]更新了Swift 4语法,并添加了uppercaseLetters的缓存,这可以提高超长字符串和紧密循环中的性能。
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.
最满意答案
据我测试我的旧MacBook,你的代码似乎对短字符串足够有效:
import Foundation extension String { var camelCaps: String { var newString: String = "" let upperCase = CharacterSet.uppercaseLetters for scalar in self.unicodeScalars { if upperCase.contains(scalar) { newString.append(" ") } let character = Character(scalar) newString.append(character) } return newString } var camelCaps2: String { var newString: String = "" let upperCase = CharacterSet.uppercaseLetters var range = self.startIndex..<self.endIndex while let foundRange = self.rangeOfCharacter(from: upperCase,range: range) { newString += self.substring(with: range.lowerBound..<foundRange.lowerBound) newString += " " newString += self.substring(with: foundRange) range = foundRange.upperBound..<self.endIndex } newString += self.substring(with: range) return newString } var camelCaps3: String { struct My { static let regex = try! NSRegularExpression(pattern: "[A-Z]") } return My.regex.stringByReplacingMatches(in: self, range: NSRange(0..<self.utf16.count), withTemplate: " $0") } } let aCamelCaps = "aCamelCaps" assert(aCamelCaps.camelCaps == aCamelCaps.camelCaps2) assert(aCamelCaps.camelCaps == aCamelCaps.camelCaps3) let t0 = Date().timeIntervalSinceReferenceDate for _ in 0..<1_000_000 { let aCamelCaps = "aCamelCaps" let camelCapped = aCamelCaps.camelCaps } let t1 = Date().timeIntervalSinceReferenceDate print(t1-t0) //->4.78703999519348 for _ in 0..<1_000_000 { let aCamelCaps = "aCamelCaps" let camelCapped = aCamelCaps.camelCaps2 } let t2 = Date().timeIntervalSinceReferenceDate print(t2-t1) //->10.5831440091133 for _ in 0..<1_000_000 { let aCamelCaps = "aCamelCaps" let camelCapped = aCamelCaps.camelCaps3 } let t3 = Date().timeIntervalSinceReferenceDate print(t3-t2) //->14.2085000276566(不要试图在Playground中测试上面的代码,这些数字是从作为CommandLine应用程序执行的单个试验中获取的。)
As far as I tested on my old MacBook, your code seems to be efficient enough for short strings:
import Foundation extension String { var camelCaps: String { var newString: String = "" let upperCase = CharacterSet.uppercaseLetters for scalar in self.unicodeScalars { if upperCase.contains(scalar) { newString.append(" ") } let character = Character(scalar) newString.append(character) } return newString } var camelCaps2: String { var newString: String = "" let upperCase = CharacterSet.uppercaseLetters var range = self.startIndex..<self.endIndex while let foundRange = self.rangeOfCharacter(from: upperCase,range: range) { newString += self.substring(with: range.lowerBound..<foundRange.lowerBound) newString += " " newString += self.substring(with: foundRange) range = foundRange.upperBound..<self.endIndex } newString += self.substring(with: range) return newString } var camelCaps3: String { struct My { static let regex = try! NSRegularExpression(pattern: "[A-Z]") } return My.regex.stringByReplacingMatches(in: self, range: NSRange(0..<self.utf16.count), withTemplate: " $0") } } let aCamelCaps = "aCamelCaps" assert(aCamelCaps.camelCaps == aCamelCaps.camelCaps2) assert(aCamelCaps.camelCaps == aCamelCaps.camelCaps3) let t0 = Date().timeIntervalSinceReferenceDate for _ in 0..<1_000_000 { let aCamelCaps = "aCamelCaps" let camelCapped = aCamelCaps.camelCaps } let t1 = Date().timeIntervalSinceReferenceDate print(t1-t0) //->4.78703999519348 for _ in 0..<1_000_000 { let aCamelCaps = "aCamelCaps" let camelCapped = aCamelCaps.camelCaps2 } let t2 = Date().timeIntervalSinceReferenceDate print(t2-t1) //->10.5831440091133 for _ in 0..<1_000_000 { let aCamelCaps = "aCamelCaps" let camelCapped = aCamelCaps.camelCaps3 } let t3 = Date().timeIntervalSinceReferenceDate print(t3-t2) //->14.2085000276566(Do not try to test the code above in the Playground. The numbers are taken from a single trial executed as a CommandLine app.)
将CamelCase字符串分隔为Swift中空格分隔的单词(Separating CamelCase string into space-separated words in Swift)我想将一个CamelCase字符串分隔成一个新字符串中的空格分隔的单词。 这是我到目前为止:
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"我倾向于怀疑,如果我将它称为紧密循环或1000年的时间,这可能不是转换为空间分隔词的最有效方式。 在Swift中有更有效的方法吗?
[编辑1:]我需要的解决方案对Unicode标量应该保持通用,而不是特定于罗马ASCII“A..Z”。
[编辑2:]解决方案也应该跳过第一个字母,即不要在第一个字母前加一个空格。
[编辑3:]更新了Swift 4语法,并添加了uppercaseLetters的缓存,这可以提高超长字符串和紧密循环中的性能。
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.
最满意答案
据我测试我的旧MacBook,你的代码似乎对短字符串足够有效:
import Foundation extension String { var camelCaps: String { var newString: String = "" let upperCase = CharacterSet.uppercaseLetters for scalar in self.unicodeScalars { if upperCase.contains(scalar) { newString.append(" ") } let character = Character(scalar) newString.append(character) } return newString } var camelCaps2: String { var newString: String = "" let upperCase = CharacterSet.uppercaseLetters var range = self.startIndex..<self.endIndex while let foundRange = self.rangeOfCharacter(from: upperCase,range: range) { newString += self.substring(with: range.lowerBound..<foundRange.lowerBound) newString += " " newString += self.substring(with: foundRange) range = foundRange.upperBound..<self.endIndex } newString += self.substring(with: range) return newString } var camelCaps3: String { struct My { static let regex = try! NSRegularExpression(pattern: "[A-Z]") } return My.regex.stringByReplacingMatches(in: self, range: NSRange(0..<self.utf16.count), withTemplate: " $0") } } let aCamelCaps = "aCamelCaps" assert(aCamelCaps.camelCaps == aCamelCaps.camelCaps2) assert(aCamelCaps.camelCaps == aCamelCaps.camelCaps3) let t0 = Date().timeIntervalSinceReferenceDate for _ in 0..<1_000_000 { let aCamelCaps = "aCamelCaps" let camelCapped = aCamelCaps.camelCaps } let t1 = Date().timeIntervalSinceReferenceDate print(t1-t0) //->4.78703999519348 for _ in 0..<1_000_000 { let aCamelCaps = "aCamelCaps" let camelCapped = aCamelCaps.camelCaps2 } let t2 = Date().timeIntervalSinceReferenceDate print(t2-t1) //->10.5831440091133 for _ in 0..<1_000_000 { let aCamelCaps = "aCamelCaps" let camelCapped = aCamelCaps.camelCaps3 } let t3 = Date().timeIntervalSinceReferenceDate print(t3-t2) //->14.2085000276566(不要试图在Playground中测试上面的代码,这些数字是从作为CommandLine应用程序执行的单个试验中获取的。)
As far as I tested on my old MacBook, your code seems to be efficient enough for short strings:
import Foundation extension String { var camelCaps: String { var newString: String = "" let upperCase = CharacterSet.uppercaseLetters for scalar in self.unicodeScalars { if upperCase.contains(scalar) { newString.append(" ") } let character = Character(scalar) newString.append(character) } return newString } var camelCaps2: String { var newString: String = "" let upperCase = CharacterSet.uppercaseLetters var range = self.startIndex..<self.endIndex while let foundRange = self.rangeOfCharacter(from: upperCase,range: range) { newString += self.substring(with: range.lowerBound..<foundRange.lowerBound) newString += " " newString += self.substring(with: foundRange) range = foundRange.upperBound..<self.endIndex } newString += self.substring(with: range) return newString } var camelCaps3: String { struct My { static let regex = try! NSRegularExpression(pattern: "[A-Z]") } return My.regex.stringByReplacingMatches(in: self, range: NSRange(0..<self.utf16.count), withTemplate: " $0") } } let aCamelCaps = "aCamelCaps" assert(aCamelCaps.camelCaps == aCamelCaps.camelCaps2) assert(aCamelCaps.camelCaps == aCamelCaps.camelCaps3) let t0 = Date().timeIntervalSinceReferenceDate for _ in 0..<1_000_000 { let aCamelCaps = "aCamelCaps" let camelCapped = aCamelCaps.camelCaps } let t1 = Date().timeIntervalSinceReferenceDate print(t1-t0) //->4.78703999519348 for _ in 0..<1_000_000 { let aCamelCaps = "aCamelCaps" let camelCapped = aCamelCaps.camelCaps2 } let t2 = Date().timeIntervalSinceReferenceDate print(t2-t1) //->10.5831440091133 for _ in 0..<1_000_000 { let aCamelCaps = "aCamelCaps" let camelCapped = aCamelCaps.camelCaps3 } let t3 = Date().timeIntervalSinceReferenceDate print(t3-t2) //->14.2085000276566(Do not try to test the code above in the Playground. The numbers are taken from a single trial executed as a CommandLine app.)
发布评论