Python で snake case → camel case

仕事で、snake case 文字列/単語を、camel case にする作業はかなりあって、
たいへん面倒くさい作業になる。
Python で実行する方法をネット検索すると結構いろんなコーディングに出くわす。

よく見かける方法。。。

import re
str = "abc_def_ghi_2j"
res = re.sub("_(.)", lambda m:m.group(1).upper(), str)
print("%s → %s" % (str, res))

たしかにこの結果は、

abc_def_ghi_2j → abcDefGhi2j

になるが、snake case 文字列がすべて大文字だったらダメだ!

str = "ABC_DEF_GHI_2J"
res = re.sub("_(.)", lambda m:m.group(1).upper(), str)
print("%s → %s" % (str, res))

この結果は、

ABC_DEF_GHI_2J → ABCDEFGHI2J

これでは、camel case とは言えない!
それならば、lower() 実行してから処理するように書けば、、

res = re.sub("_(.)", lambda m:m.group(1).upper(), str.lower())
print("%s → %s" % (str, res))

結果は、、、

ABC_DEF_GHI_2J → abcDefGhi2j

データーベースの列名が snake case で、Java の Objectコードでは、
camel case で小文字が先頭という要求仕様で、
先頭1文字が小文字をであることを望むであろうが、
でも、、稀に、先頭1文字が大文字を望むこともあるだろう。。

先頭1文字が大文字の camel case が欲しい場合、上の方法ではなく原始的な split('_') の結果で
処理するのが次の方法だ。

res = ''.join(x.title() for x in str.split('_'))
print("%s → %s" % (str, res))

結果は、

ABC_DEF_GHI_2J → AbcDefGhi2J

title() を使ってるので、"2J" は、そのまま、"2J" で、厳密に1文字目を大文字、後ろを小文字なら、
capitalize() を使うべきで、、、

res = ''.join(x.capitalize() for x in str.split('_'))
print("%s → %s" % (str, res))

capitalize() 使用の結果は、、

ABC_DEF_GHI_2J → AbcDefGhi2j

である。
または、別の考えで、先頭1文字だけが大文字を望む場合は、、

res = str.title().replace("_", "")
print("%s → %s" % (str, res))

とすると

ABC_DEF_GHI_2J → AbcDefGhi2J

数字を無視して飛ばして次の文字を適用させるべきなのか
良くわからない!
そんなこと論争したら、宗教戦争みたいなことになりかねない。。

こんなにもいろんな方法があると、先頭1文字が大文字か小文字か?
メソッドとしてまとめておくのが、良いようだ。。

def toCamelCase(string, titleCase=False):
    import re
    if titleCase:
        return ''.join(x.title() for x in string.split('_'))
    else:
        return re.sub("_(.)", lambda m:m.group(1).upper(), string.lower())

第1引数に、snake case 文字列
第2引数に、先頭1文字が大文字なら、True を指定する。