-
-
Save sidharthkuruvila/3154845 to your computer and use it in GitHub Desktop.
/** | |
* Takes a camel cased identifier name and returns an underscore separated | |
* name | |
* | |
* Example: | |
* camelToUnderscores("thisIsA1Test") == "this_is_a_1_test" | |
*/ | |
def camelToUnderscores(name: String) = "[A-Z\\d]".r.replaceAllIn(name, {m => | |
"_" + m.group(0).toLowerCase() | |
}) | |
/* | |
* Takes an underscore separated identifier name and returns a camel cased one | |
* | |
* Example: | |
* underscoreToCamel("this_is_a_1_test") == "thisIsA1Test" | |
*/ | |
def underscoreToCamel(name: String) = "_([a-z\\d])".r.replaceAllIn(name, {m => | |
m.group(1).toUpperCase() | |
}) |
@dmateusp FYI, that causes a problem with things like camelToSnake("IsAString") => is_astring, when it should be is_a_string.
I prefer not to use regex, this approach runs in n time, it's tail recursive and does not convert consecutive upper chars, e.g. ThisIsCAmel -> this_is_camel:
def camel2Underscore(s: String): String = {
@tailrec def camel2Underscore(s: String, output: String, lastUppercase: Boolean): String =
if (s.isEmpty) output
else {
val c = if (s.head.isUpper && !lastUppercase) "_" + s.head.toLower else s.head.toLower
camel2Underscore(s.tail, output + c, s.head.isUpper && !lastUppercase)
}
camel2Underscore(s, "", true)
}
@ruloweb This is nice but won't work if the two consecutive uppercase chars are at the start (ie. THisIsCamel) or if there are greater than two consecutive uppercase characters elsewhere (ie. ThisIsCAMel). Consequently, this will fail for converting all caps as well.
I adjusted the code to support the all caps case:
def camel2Snake(str: String): String = {
@tailrec
def camel2SnakeRec(s: String, output: String, lastUppercase: Boolean): String =
if (s.isEmpty) output
else {
val c = if (s.head.isUpper && !lastUppercase) "_" + s.head.toLower else s.head.toLower
camel2SnakeRec(s.tail, output + c, s.head.isUpper && !lastUppercase)
}
if (str.forall(_.isUpper)) str.map(_.toLower)
else {
camel2SnakeRec(str, "", true)
}
}
@amackillop, it doesnt't work for "THISIsADog" (it gives "t_hi_sis_adog")
i suggest the following code :
def camel2Snake(str: String): String = {
val headInUpperCase = str.takeWhile(c => c.isUpper || c.isDigit)
val tailAfterHeadInUppercase = str.dropWhile(c => c.isUpper || c.isDigit)
if (tailAfterHeadInUppercase.isEmpty) headInUpperCase.toLowerCase else {
val firstWord = if (!headInUpperCase.dropRight(1).isEmpty) {
headInUpperCase.last match {
case c: Any if (c.isDigit) => headInUpperCase
case _ => headInUpperCase.dropRight(1).toLowerCase
}
} else {
headInUpperCase.toLowerCase + tailAfterHeadInUppercase.takeWhile(c => c.isLower)
}
if (firstWord == str.toLowerCase) {
firstWord
} else {
s"${firstWord}_${camel2Snake(str.drop(firstWord.length))}"
}
}
}
@0dilon you version stack-overflows if the camelCase already contains an underscore.
e.g. camel2Snake("foo_BarBaz")
Late to the party, but iterate w/ Char
s seems fine too if you're ok w/ no handling -
s in the String
s
val camelToKebab: String => String = _.foldLeft("") {
case (acc, chr) if chr.isUpper => acc :+ '-' :+ chr.toLower
case (acc, chr) => acc :+ chr
}
val camelToSnake : String => String = _.foldLeft( "" ){ (acc, c) =>
( c.isUpper, acc.isEmpty, acc.takeRight(1) == "_" ) match {
case (true, false, false) => acc + "_" + c.toLower
case (true, _, _) => acc + c.toLower
case (false, _, _) => acc + c
}
}
@dmateusp 👍 exactly what I needed! Would be great if worked with numeric text:
actual: DirectlyEmployedOr1099Resources => directly_employed_or1099resources
expected: DirectlyEmployedOr1099Resources => directly_employed_or_1099_resources