CamelCase를 snake_case로 변환하는 우아한 Python 함수?
예:
>>> convert('CamelCase')
'camel_case'
카멜 케이스에서 뱀 케이스로
import re
name = 'CamelCaseName'
name = re.sub(r'(?<!^)(?=[A-Z])', '_', name).lower()
print(name) # camel_case_name
이 작업을 여러 번 수행하고 위의 작업이 느릴 경우 미리 regex를 컴파일하십시오.
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
두 개 이상의 밑줄이 있는 대소문자를 추가하려면:
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
패키지 인덱스에는 이러한 작업을 처리할 수 있는 변곡 라이브러리가 있습니다.이 경우, 다음과 같이 됩니다.
>>> inflection.underscore('CamelCase')
'camel_case'
왜 이렇게 복잡한지 모르겠어요.
의 경우,은 "" " " " " " 입니다. " 입니다.([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'
.ALCaps all_caps _ alc alc alc alc 。|
은 「」입니다.((?<=[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!
라이브러리 및 정규 표현 회피:
def camel_to_snake(s):
return ''.join(['_'+c.lower() if c.isupper() else c for c in s]).lstrip('_')
>>> camel_to_snake('ThisIsMyString')
'this_is_my_string'
stringcase는 이를 위한 사용 라이브러리입니다.예:
>>> from stringcase import pascalcase, snakecase
>>> snakecase('FooBarBaz')
'foo_bar_baz'
>>> pascalcase('foo_bar_baz')
'FooBarBaz'
저는 이 솔루션이 이전 답변보다 더 간단하다고 생각합니다.
import re
def convert (camel_input):
words = re.findall(r'[A-Z]?[a-z]+|[A-Z]{2,}(?=[A-Z][a-z]|\d|\W|$)|\d+', camel_input)
return '_'.join(map(str.lower, words))
# Let's test it
test_strings = [
'CamelCase',
'camelCamelCase',
'Camel2Camel2Case',
'getHTTPResponseCode',
'get200HTTPResponseCode',
'getHTTP200ResponseCode',
'HTTPResponseCode',
'ResponseHTTP',
'ResponseHTTP2',
'Fun?!awesome',
'Fun?!Awesome',
'10CoolDudes',
'20coolDudes'
]
for test_string in test_strings:
print(convert(test_string))
출력:
camel_case
camel_camel_case
camel_2_camel_2_case
get_http_response_code
get_200_http_response_code
get_http_200_response_code
http_response_code
response_http
response_http_2
fun_awesome
fun_awesome
10_cool_dudes
20_cool_dudes
정규 표현은 다음 3가지 패턴과 일치합니다.
[A-Z]?[a-z]+
: 옵션으로 대문자로 시작하는 연속되는 소문자.[A-Z]{2,}(?=[A-Z][a-z]|\d|\W|$)
: 2번입니다.마지막 대문자 뒤에 소문자가 이어지는 경우 미리 보기를 사용하여 제외합니다.\d+
: 연속번호.
「」를 사용해 .re.findall
소문자로 변환하여 밑줄로 묶을 수 있는 개별 "단어" 목록을 얻을 수 있습니다.
개인적으로 파이썬에서 정규 표현을 사용하는 것이 어떻게 우아하게 묘사될 수 있을지 모르겠다.대부분의 답은 "코드 골프" 타입의 RE 트릭을 하는 것뿐입니다.우아한 코딩은 쉽게 이해될 것이다.
def to_snake_case(not_snake_case):
final = ''
for i in xrange(len(not_snake_case)):
item = not_snake_case[i]
if i < len(not_snake_case) - 1:
next_char_will_be_underscored = (
not_snake_case[i+1] == "_" or
not_snake_case[i+1] == " " or
not_snake_case[i+1].isupper()
)
if (item == " " or item == "_") and next_char_will_be_underscored:
continue
elif (item == " " or item == "_"):
final += "_"
elif item.isupper():
final += "_"+item.lower()
else:
final += item
if final[0] == "_":
final = final[1:]
return final
>>> to_snake_case("RegularExpressionsAreFunky")
'regular_expressions_are_funky'
>>> to_snake_case("RegularExpressionsAre Funky")
'regular_expressions_are_funky'
>>> to_snake_case("RegularExpressionsAre_Funky")
'regular_expressions_are_funky'
''.join('_'+c.lower() if c.isupper() else c for c in "DeathToCamelCase").strip('_')
re.sub("(.)([A-Z])", r'\1_\2', 'DeathToCamelCase').lower()
제 해결책은 다음과 같습니다.
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
그래야 할 것처럼요
왜 둘 다 .sub() 콜을 사용하는지 모르겠어요.:) regex guru는 아니지만 특정 요구에 맞는 기능을 이 기능으로 단순화했습니다.post 요청에서 vars_with_underscore로 camelCasedVars를 변환하는 솔루션이 필요했을 뿐입니다.
def myFunc(...):
return re.sub('(.)([A-Z]{1})', r'\1_\2', "iTriedToWriteNicely").lower()
get과 같은 이름에서는 동작하지 않습니다.HTTPResponse는 나쁜 명명규칙이라고 들었기 때문에 (getHttpResponse와 같아야 합니다.이 폼을 외우기 쉽다는 것은 명백합니다).
재미삼아:
>>> 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'
정규식을 사용하는 것이 가장 짧을 수 있지만 이 솔루션은 훨씬 읽기 쉽습니다.
def to_snake_case(s):
snake = "".join(["_"+c.lower() if c.isupper() else c for c in s])
return snake[1:] if snake.startswith("_") else snake
이것은 우아한 방법이 아니라 간단한 스테이트 머신(비트필드 스테이트 머신)의 매우 '저레벨' 구현이며, 아마도 이것을 해결하기 위한 가장 반피토닉 모드일 것입니다만, re module도 이 단순한 태스크를 해결하기 위해 너무 복잡한 스테이트 머신을 구현하고 있기 때문에 좋은 해결책이라고 생각합니다.
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 및 cammelCased 메서드
유용했으면 좋겠다
뛰어난 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')
복잡한 방법들이 너무 많아서...모든 "제목" 그룹을 찾고 밑줄로 구분된 하위 버전을 결합하기만 하면 됩니다.
>>> import re
>>> def camel_to_snake(string):
... groups = re.findall('([A-z0-9][a-z]*)', string)
... return '_'.join([i.lower() for i in groups])
...
>>> camel_to_snake('ABCPingPongByTheWay2KWhereIsOurBorderlands3???')
'a_b_c_ping_pong_by_the_way_2_k_where_is_our_borderlands_3'
의 첫 숫자를 않은 에는 '어울면 안 돼요'를 사용하면 .([A-z][a-z0-9]*)
mask.mask.mask.mask.
정규 표현을 사용한 끔찍한 예(이것을 간단하게 정리할 수 있습니다:
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")
취득에 효과적이다단, HTTPResponse Code!
또는 람다를 사용하여 다음을 수행합니다.
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")
편집: 또, 「테스트」등의 경우는, 언더 스코어가 무조건 삽입되어 있기 때문에, 개선의 여지가 있는 것을 알 수 있습니다.
발전기를 사용하는 https://stackoverflow.com/users/267781/matth에서 Lightely를 채택했습니다.
def uncamelize(s):
buff, l = '', []
for ltr in s:
if ltr.isupper():
if buff:
l.append(buff)
buff = ''
buff += ltr
l.append(buff)
return '_'.join(l).lower()
다음과 같은 간단한 방법으로 작업을 수행할 수 있습니다.
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()
- 임의의 수의 대문자(또는 제로) 앞에 임의의 수의 소문자가 이어지는 대문자를 찾습니다.
- 그룹에서 발견된 마지막 대문자 발생 직전에 밑줄이 표시되며, 다른 대문자 뒤에 있는 경우 해당 대문자 앞에 밑줄을 넣을 수 있습니다.
- 뒤에 밑줄이 있는 경우 제거합니다.
- 마지막으로 결과 문자열 전체를 소문자로 변경합니다.
다음은 탭 구분 파일의 헤더를 변경하기 위한 작업입니다.파일의 첫 줄만 편집한 부분은 생략하고 있습니다.re 라이브러리를 사용하면 Python에 쉽게 적응할 수 있습니다.여기에는 숫자 분리도 포함됩니다(단, 숫자를 함께 유지합니다).줄이나 탭의 시작 부분에 밑줄을 그리지 말라고 말하는 것보다 더 쉬웠기 때문에 두 단계로 진행했습니다.
스텝 1...소문자 앞에 대문자 또는 정수를 찾고 그 앞에 밑줄을 그립니다.
검색:
([a-z]+)([A-Z]|[0-9]+)
교환:
\1_\l\2/
스텝 2...위의 명령어를 다시 실행하여 모든 대소문자를 소문자로 변환합니다.
검색:
([A-Z])
대체(백슬래시, 소문자 L, 백슬래시, 1):
\l\1
같은 문제에 대한 해결책을 찾고 있었지만 체인이 필요했습니다.
"CamelCamelCamelCase" -> "Camel-camel-camel-case"
이 두 단어로 이루어진 멋진 솔루션에서 저는 다음과 같은 아이디어를 얻었습니다.
"-".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"))
물론 다른 솔루션에서 설명한 것처럼 정규 표현을 미리 컴파일하거나 하이픈 대신 밑줄로 결합할 수 있습니다.
정규 표현 없이 간결하지만 HTTP ResponseCode=> httpresponse_code:
def from_camel(name):
"""
ThisIsCamelCase ==> this_is_camel_case
"""
name = name.replace("_", "")
_cas = lambda _x : [_i.isupper() for _i in _x]
seq = zip(_cas(name[1:-1]), _cas(name[2:]))
ss = [_x + 1 for _x, (_i, _j) in enumerate(seq) if (_i, _j) == (False, True)]
return "".join([ch + "_" if _x in ss else ch for _x, ch in numerate(name.lower())])
라이브러리가 없는 경우
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
이 사이트에서 제안하는 RegEx는 매우 훌륭합니다.
(?<!^)(?=[A-Z])
python이 String Split 메서드를 사용하는 경우 동작합니다.
자바어:
String s = "loremIpsum";
words = s.split("(?<!^)(?=[A-Z])");
완전한 소스 파일을 변환해야 하는 경우에 대비하여 다음 스크립트가 있습니다.
# 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))
장고 토막에서 이걸 훔쳤어참조: 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'
def convert(name):
return reduce(
lambda x, y: x + ('_' if y.isupper() else '') + y,
name
).lower()
또한 이미 캠이 없는 입력으로 사례를 처리해야 하는 경우:
def convert(name):
return reduce(
lambda x, y: x + ('_' if y.isupper() and not x.endswith('_') else '') + y,
name
).lower()
표준 라이브러리에는 없지만 필요한 기능이 포함된 이 모듈을 찾았습니다.
Google의 (거의) 결정론적 Camel 케이스 알고리즘을 사용하면 다음과 같은 것을 처리할 필요가 없습니다.HTMLDocument
HtmlDocument
정규식입니다.모든 대문자 또는 숫자를 밑줄로 바꿉니다.노트에서는 여러 자리 숫자는 처리되지 않습니다.
import re
def to_snake_case(camel_str):
return re.sub('([A-Z0-9])', r'_\1', camel_str).lower().lstrip('_')
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()
문자열의 첫 글자(변수 스트링에 포함)를 대문자로 변환하고 문자열 전체를 반환합니다.
예: 명령어: "hello".capitalize() 출력:안녕하세요.
언급URL : https://stackoverflow.com/questions/1175208/elegant-python-function-to-convert-camelcase-to-snake-case
'programing' 카테고리의 다른 글
Laravel first 아니면 새 제품인지 확인하는 방법? (0) | 2022.10.27 |
---|---|
phpmyadmin에서 외부 키를 만드는 방법 (0) | 2022.10.27 |
Vuex에서 매개 변수화된 getter - 트리거 udpate (0) | 2022.10.27 |
다른 열의 MAX 값에 해당하는 열 값을 가져오기 위한 SQL 쿼리입니까? (0) | 2022.10.27 |
'System' 유형의 COM 개체를 캐스팅할 수 없습니다.__ComObject'에서 인터페이스 유형으로 (0) | 2022.10.27 |