Create a gist now

Instantly share code, notes, and snippets.

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()
})
@samthebest

You shouldn't include digits when converting between camel and underscores, by definition there is no such thing as an upper case digit, and therefore it doesn't make sense to consider a digit a capitalised separate word.

@eallik
eallik commented Jan 13, 2015

your algorithm doesn't correctly map _FOO_BAR to _FooBar and vice versa; here's my attempt at it:

def underscores2camel(name: String) = {
  assert(!(name endsWith "_"), "names ending in _ not supported by this algorithm")
  "[A-Za-z\\d]+_?|_".r.replaceAllIn(name, { x =>
    val x0 = x.group(0)
    if (x0 == "_") x0
    else x0.stripSuffix("_").toLowerCase.capitalize
  })
}
def camel2underscores(x: String) = {
  "_?[A-Z][a-z\\d]+".r.findAllMatchIn(x).map(_.group(0).toLowerCase).mkString("_")
}
@ry4nz
ry4nz commented Mar 27, 2015

scala> camel2underscores("CamelCaseF")
res37: String = camel_case

@zucaritask

@eallik, your algorithm returns "" for a non-camelcased string

scala> camel2underscores("foobar")
res1: String = ""
@DeaconDesperado

To avoid the leading _:

  def camelToUnderscores(name: String) = "[A-Z\\d]".r.replaceAllIn(name, {m =>
    if(m.end(0) == 1){
      m.group(0).toLowerCase()
    }else {
      "_" + m.group(0).toLowerCase()
    }
  })
@asheshambasta
asheshambasta commented Aug 11, 2016 edited

Maybe a little less concise but I prefer this;

def camel2Underscore(text: String) = text.drop(1).foldLeft(text.headOption.map(_.toLower + "") getOrElse "") {
  case (acc, c) if c.isUpper => acc + "_" + c.toLower
  case (acc, c) => acc + c
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment