例:
>>> convert('CamelCase')
'camel_case'
import re
name = 'CamelCaseName'
name = re.sub(r'(?<!^)(?=[A-Z])', '_', name).lower()
print(name) # camel_case_name
これを何度も行い、上記が遅い場合は、事前に正規表現をコンパイルしてください。
pattern = re.compile(r'(?<!^)(?=[A-Z])')
name = pattern.sub('_', name).lower()
より高度なケースを特別に処理するには (これは元に戻すことはできません):
def camel_to_snake(name):
name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower()
print(camel_to_snake('camel2_camel2_case')) # camel2_camel2_case
print(camel_to_snake('getHTTPResponseCode')) # get_http_response_code
print(camel_to_snake('HTTPResponseCodeXYZ')) # http_response_code_xyz
アンダースコアが 2 つ以上のケースも追加するには:
def to_snake_case(name):
name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
name = re.sub('__([A-Z])', r'_\1', name)
name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', name)
return name.lower()
name = 'snake_case_name'
name = ''.join(word.title() for word in name.split('_'))
print(name) # SnakeCaseName
なぜこれらすべてがそれほど複雑なのかわかりません。
ほとんどの場合、単純な式([A-Z]+)
でうまくいきます
>>> re.sub('([A-Z]+)', r'_\1','CamelCase').lower()
'_camel_case'
>>> re.sub('([A-Z]+)', r'_\1','camelCase').lower()
'camel_case'
>>> re.sub('([A-Z]+)', r'_\1','camel2Case2').lower()
'camel2_case2'
>>> re.sub('([A-Z]+)', r'_\1','camelCamelCase').lower()
'camel_camel_case'
>>> re.sub('([A-Z]+)', r'_\1','getHTTPResponseCode').lower()
'get_httpresponse_code'
最初の文字を無視するには、後ろ向きを追加するだけです(?!^)
>>> re.sub('(?!^)([A-Z]+)', r'_\1','CamelCase').lower()
'camel_case'
>>> re.sub('(?!^)([A-Z]+)', r'_\1','CamelCamelCase').lower()
'camel_camel_case'
>>> re.sub('(?!^)([A-Z]+)', r'_\1','Camel2Camel2Case').lower()
'camel2_camel2_case'
>>> re.sub('(?!^)([A-Z]+)', r'_\1','getHTTPResponseCode').lower()
'get_httpresponse_code'
ALLCaps を all_caps に分離し、文字列に数値を期待する場合でも、2 つの別々の実行を行う必要はありません。|
この式((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))
は、本のほぼすべてのシナリオを処理できます。
>>> a = re.compile('((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))')
>>> a.sub(r'_\1', 'getHTTPResponseCode').lower()
'get_http_response_code'
>>> a.sub(r'_\1', 'get2HTTPResponseCode').lower()
'get2_http_response_code'
>>> a.sub(r'_\1', 'get2HTTPResponse123Code').lower()
'get2_http_response123_code'
>>> a.sub(r'_\1', 'HTTPResponseCode').lower()
'http_response_code'
>>> a.sub(r'_\1', 'HTTPResponseCodeXYZ').lower()
'http_response_code_xyz'
それはすべてあなたが望むものに依存するので、過度に複雑であってはならないので、あなたのニーズに最も適したソリューションを使用してください.
nJoy!
''.join('_'+c.lower() if c.isupper() else c for c in "DeathToCamelCase").strip('_')
re.sub("(.)([A-Z])", r'\1_\2', 'DeathToCamelCase').lower()
両方の .sub() 呼び出しを使用する理由がわかりませんか? :) 私は正規表現の第一人者ではありませんが、特定のニーズに適した関数をこれに単純化しました。camelCasedVars を POST リクエストから vars_with_underscore に変換するソリューションが必要でした:
def myFunc(...):
return re.sub('(.)([A-Z]{1})', r'\1_\2', "iTriedToWriteNicely").lower()
getHTTPResponse のような名前では機能しません。命名規則が悪いと聞いたからです (getHttpResponse のようにする必要があります。明らかに、この形式を覚える方がはるかに簡単です)。
これが私の解決策です:
def un_camel(text):
""" Converts a CamelCase name into an under_score name.
>>> un_camel('CamelCase')
'camel_case'
>>> un_camel('getHTTPResponseCode')
'get_http_response_code'
"""
result = []
pos = 0
while pos < len(text):
if text[pos].isupper():
if pos-1 > 0 and text[pos-1].islower() or pos-1 > 0 and \
pos+1 < len(text) and text[pos+1].islower():
result.append("_%s" % text[pos].lower())
else:
result.append(text[pos].lower())
else:
result.append(text[pos])
pos += 1
return "".join(result)
コメントで説明されているコーナーケースをサポートします。たとえば、必要に応じて変換getHTTPResponseCode
されますget_http_response_code
。
楽しみのために:
>>> def un_camel(input):
... output = [input[0].lower()]
... for c in input[1:]:
... if c in ('ABCDEFGHIJKLMNOPQRSTUVWXYZ'):
... output.append('_')
... output.append(c.lower())
... else:
... output.append(c)
... return str.join('', output)
...
>>> un_camel("camel_case")
'camel_case'
>>> un_camel("CamelCase")
'camel_case'
または、それをもっと楽しむために:
>>> un_camel = lambda i: i[0].lower() + str.join('', ("_" + c.lower() if c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ" else c for c in i[1:]))
>>> un_camel("camel_case")
'camel_case'
>>> un_camel("CamelCase")
'camel_case'
これは洗練された方法ではなく、単純なステートマシン(ビットフィールドステートマシン)の非常に「低レベル」の実装であり、おそらくこれを解決するための最もアンチpythonicモードですが、reモジュールはこの単純な状態を解決するには複雑すぎるステートマシンも実装しますタスクなので、これは良い解決策だと思います。
def splitSymbol(s):
si, ci, state = 0, 0, 0 # start_index, current_index
'''
state bits:
0: no yields
1: lower yields
2: lower yields - 1
4: upper yields
8: digit yields
16: other yields
32 : upper sequence mark
'''
for c in s:
if c.islower():
if state & 1:
yield s[si:ci]
si = ci
elif state & 2:
yield s[si:ci - 1]
si = ci - 1
state = 4 | 8 | 16
ci += 1
elif c.isupper():
if state & 4:
yield s[si:ci]
si = ci
if state & 32:
state = 2 | 8 | 16 | 32
else:
state = 8 | 16 | 32
ci += 1
elif c.isdigit():
if state & 8:
yield s[si:ci]
si = ci
state = 1 | 4 | 16
ci += 1
else:
if state & 16:
yield s[si:ci]
state = 0
ci += 1 # eat ci
si = ci
print(' : ', c, bin(state))
if state:
yield s[si:ci]
def camelcaseToUnderscore(s):
return '_'.join(splitSymbol(s))
splitsymbolは、すべてのケースタイプを解析できます:UpperSEQUENCEInterleaved、under_score、BIG_SYMBOLS、およびcammelCasedMethods
お役に立てば幸いです
正規表現を使用した恐ろしい例 (これは簡単に片付けることができます :) ):
def f(s):
return s.group(1).lower() + "_" + s.group(2).lower()
p = re.compile("([A-Z]+[a-z]+)([A-Z]?)")
print p.sub(f, "CamelCase")
print p.sub(f, "getHTTPResponseCode")
ただし、getHTTPResponseCode では機能します。
または、ラムダを使用します。
p = re.compile("([A-Z]+[a-z]+)([A-Z]?)")
print p.sub(lambda x: x.group(1).lower() + "_" + x.group(2).lower(), "CamelCase")
print p.sub(lambda x: x.group(1).lower() + "_" + x.group(2).lower(), "getHTTPResponseCode")
編集:アンダースコアが無条件に挿入されるため、「テスト」のような場合には改善の余地があることも簡単にわかるはずです。
この簡単な方法で仕事をする必要があります。
import re
def convert(name):
return re.sub(r'([A-Z]*)([A-Z][a-z]+)', lambda x: (x.group(1) + '_' if x.group(1) else '') + x.group(2) + '_', name).rstrip('_').lower()
優れた Schematics lib を見てみましょう
https://github.com/schematics/schematics
Python から Javascript フレーバーにシリアライズ/デシリアライズできる型付きデータ構造を作成できます。
class MapPrice(Model):
price_before_vat = DecimalType(serialized_name='priceBeforeVat')
vat_rate = DecimalType(serialized_name='vatRate')
vat = DecimalType()
total_price = DecimalType(serialized_name='totalPrice')
タブ区切りファイルのヘッダーを変更するために行ったことを次に示します。ファイルの最初の行のみを編集した部分は省略しています。re ライブラリを使用すると、非常に簡単に Python に適応させることができます。これには、数字の分離も含まれます (ただし、数字は一緒に保持されます)。行やタブの先頭にアンダースコアを置かないように指示するよりも簡単だったので、2 つの手順で行いました。
ステップ 1...小文字が前にある大文字または整数を見つけ、それらの前にアンダースコアを付けます。
探す:
([a-z]+)([A-Z]|[0-9]+)
置換:
\1_\l\2/
ステップ 2...上記を実行して再度実行し、すべての大文字を小文字に変換します。
探す:
([A-Z])
置換 (バックスラッシュ、小文字の L、バックスラッシュ、1 つ):
\l\1
ライブラリなし:
def camelify(out):
return (''.join(["_"+x.lower() if i<len(out)-1 and x.isupper() and out[i+1].islower()
else x.lower()+"_" if i<len(out)-1 and x.islower() and out[i+1].isupper()
else x.lower() for i,x in enumerate(list(out))])).lstrip('_').replace('__','_')
少し重いですが、
CamelCamelCamelCase -> camel_camel_camel_case
HTTPRequest -> http_request
GetHTTPRequest -> get_http_request
getHTTPRequest -> get_http_request
このサイトで提案された非常に素晴らしい正規表現:
(?<!^)(?=[A-Z])
PythonにString Splitメソッドがある場合、それは機能するはずです...
Java の場合:
String s = "loremIpsum";
words = s.split("(?<!^)(?=[A-Z])");
うわー、これをジャンゴのスニペットから盗んだところです。ref http://djangosnippets.org/snippets/585/
かなりエレガント
camelcase_to_underscore = lambda str: re.sub(r'(?<=[a-z])[A-Z]|[A-Z](?=[^A-Z])', r'_\g<0>', str).lower().strip('_')
例:
camelcase_to_underscore('ThisUser')
戻り値:
'this_user'
完全なソース ファイルを変換する必要がある場合に備えて、これを実行するスクリプトを次に示します。
# Copy and paste your camel case code in the string below
camelCaseCode ="""
cv2.Matx33d ComputeZoomMatrix(const cv2.Point2d & zoomCenter, double zoomRatio)
{
auto mat = cv2.Matx33d::eye();
mat(0, 0) = zoomRatio;
mat(1, 1) = zoomRatio;
mat(0, 2) = zoomCenter.x * (1. - zoomRatio);
mat(1, 2) = zoomCenter.y * (1. - zoomRatio);
return mat;
}
"""
import re
def snake_case(name):
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
def lines(str):
return str.split("\n")
def unlines(lst):
return "\n".join(lst)
def words(str):
return str.split(" ")
def unwords(lst):
return " ".join(lst)
def map_partial(function):
return lambda values : [ function(v) for v in values]
import functools
def compose(*functions):
return functools.reduce(lambda f, g: lambda x: f(g(x)), functions, lambda x: x)
snake_case_code = compose(
unlines ,
map_partial(unwords),
map_partial(map_partial(snake_case)),
map_partial(words),
lines
)
print(snake_case_code(camelCaseCode))
チェーンが必要だったことを除いて、同じ問題の解決策を探していました。例えば
"CamelCamelCamelCase" -> "Camel-camel-camel-case"
ここにある素敵な 2 語の解決策から始めて、次のことを思いつきました。
"-".join(x.group(1).lower() if x.group(2) is None else x.group(1) \
for x in re.finditer("((^.[^A-Z]+)|([A-Z][^A-Z]+))", "stringToSplit"))
複雑なロジックのほとんどは、最初の単語を小文字にしないようにすることです。最初の単語を変更してもかまわない場合の簡単なバージョンを次に示します。
"-".join(x.group(1).lower() for x in re.finditer("(^[^A-Z]+|[A-Z][^A-Z]+)", "stringToSplit"))
もちろん、他のソリューションで説明したように、正規表現をプリコンパイルするか、ハイフンの代わりにアンダースコアで結合することができます。
標準ライブラリにはありませんが、必要な機能が含まれているように見えるこのモジュールを見つけました。
私はこれでかなり幸運でした:
import re
def camelcase_to_underscore(s):
return re.sub(r'(^|[a-z])([A-Z])',
lambda m: '_'.join([i.lower() for i in m.groups() if i]),
s)
必要に応じて、これは明らかに速度を少し最適化できます。
import re
CC2US_RE = re.compile(r'(^|[a-z])([A-Z])')
def _replace(match):
return '_'.join([i.lower() for i in match.groups() if i])
def camelcase_to_underscores(s):
return CC2US_RE.sub(_replace, s)
def convert(camel_str):
temp_list = []
for letter in camel_str:
if letter.islower():
temp_list.append(letter)
else:
temp_list.append('_')
temp_list.append(letter)
result = "".join(temp_list)
return result.lower()
使用:str.capitalize()
文字列 (変数 str に含まれる) の最初の文字を大文字に変換し、文字列全体を返します。
例: コマンド: "hello".capitalize() 出力: Hello