Skip to content

Instantly share code, notes, and snippets.

@sidharthkuruvila
Created July 21, 2012 06:30
Show Gist options
  • Save sidharthkuruvila/3154845 to your computer and use it in GitHub Desktop.
Save sidharthkuruvila/3154845 to your computer and use it in GitHub Desktop.
Utility to functions to convert between camel case and underscore separated names
/**
* 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()
})
@0dilon
Copy link

0dilon commented Dec 19, 2019

@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))}"
    }

  }
}

@nicusX
Copy link

nicusX commented Jan 2, 2020

@0dilon you version stack-overflows if the camelCase already contains an underscore.
e.g. camel2Snake("foo_BarBaz")

@jnewman
Copy link

jnewman commented May 18, 2021

Late to the party, but iterate w/ Chars seems fine too if you're ok w/ no handling -s in the Strings

val camelToKebab: String => String = _.foldLeft("") {
      case (acc, chr) if chr.isUpper => acc :+ '-' :+ chr.toLower
      case (acc, chr)                => acc :+ chr
    }

@Kalyan-D
Copy link

@0dilon you version stack-overflows if the camelCase already contains an underscore.

any update on this @0dilon

@umbarger
Copy link

umbarger commented Sep 21, 2021

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
    }
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment