Skip to content

Instantly share code, notes, and snippets.

@tatimagdalena
Last active October 19, 2023 16:02
Show Gist options
  • Save tatimagdalena/b2556d6deba5c400d4f2e46a095dadfc to your computer and use it in GitHub Desktop.
Save tatimagdalena/b2556d6deba5c400d4f2e46a095dadfc to your computer and use it in GitHub Desktop.
String extension to transform string into several case types
import Foundation
extension String {
public var upperCasedFirstLetter: String {
prefix(1).uppercased() + dropFirst()
}
public var lowerCasedFirstLetter: String {
prefix(1).lowercased() + dropFirst()
}
public func lowerCamelCased() -> String {
upperCamelCased().lowerCasedFirstLetter
}
public func upperCamelCased() -> String {
let lowerCasedSelf = lowercased()
let components = lowerCasedSelf.components(separatedBy: CharacterSet(charactersIn: " _-."))
return components.reduce("") { partialResult, word in
partialResult + word.capitalized
}
}
public func camelCaseToSnakeCase() -> String {
let components = componentsSeparatedByUppercase()
return components.map({$0.lowercased()}).joined(separator: "_")
}
public func camelCaseToDotCase() -> String {
let components = componentsSeparatedByUppercase()
return components.map({$0.lowercased()}).joined(separator: ".")
}
private func componentsSeparatedByUppercase() -> [String] {
var components: [String] = []
var currentComponent = ""
unicodeScalars.forEach { character in
if currentComponent.isEmpty.not && character.caseType == CharacterCase.upper {
components.append(currentComponent)
currentComponent = character.escaped(asASCII: false)
} else {
currentComponent += character.escaped(asASCII: false)
}
}
components.append(currentComponent)
return components
}
}
private enum CharacterCase {
case lower
case upper
case none
}
extension UnicodeScalar {
fileprivate var caseType: CharacterCase {
if CharacterSet.lowercaseLetters.contains(self) { .lower }
else if CharacterSet.uppercaseLetters.contains(self) { .upper }
else { .none }
}
}
extension Bool {
fileprivate var not: Bool { !self }
}
// MARK: - Tests -
// TODO: Move to a Test target
@testable import MyApp
import XCTest
final class StringCaseTransformTests: XCTestCase {
func testLowerCamelCased() {
let snakecaseString = "This_iS-a_string"
let lowerCamelCased = snakecaseString.lowerCamelCased()
XCTAssertEqual(lowerCamelCased, "thisIsAString")
}
func testUpperCamelCased() {
let snakecaseString = "This_iS-a_string"
let upperCamelCased = snakecaseString.upperCamelCased()
XCTAssertEqual(upperCamelCased, "ThisIsAString")
}
func testCamelCaseToSnakeCase() {
let camelcaseString = "thisIsAString"
let snakecaseString = camelcaseString.camelCaseToSnakeCase()
XCTAssertEqual(snakecaseString, "this_is_a_string")
}
func testCamelCaseToDotCase() {
let camelcaseString = "thisIsAString"
let dotcaseString = camelcaseString.camelCaseToDotCase()
XCTAssertEqual(dotcaseString, "this.is.a.string")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment