CamelCase를 snake_case로 변환하는 우아한 Python 함수?


333

예:

>>> convert('CamelCase')
'camel_case'

28
다른 방향으로 변환하려면이 다른 stackoverflow 질문을 참조하십시오 .
Nathan

10
nb NotCamelCase그래도thisIs
Matt Richards

5
@MattRichards 분쟁의 문제입니다. wiki
NO_NAME

@MattRichards 예를 들어 Java에서는 CamelCase가 클래스 정의의 이름을 지정하는 데 사용되고 camelCase는 초기화 된 변수의 이름을 지정하는 데 사용됩니다.
darkless

답변:


797

낙타 케이스에서 뱀 케이스로

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

뱀 케이스에서 낙타 케이스

name = 'snake_case_name'
name = ''.join(word.title() for word in name.split('_'))
print(name)  # SnakeCaseName

1
이 솔루션은 _test_Method, __test__Method, _Test, getHTTPresponseCode, __CamelCase 및 _Camel_Case와 같은 경우에 실패합니다.
freegnu

6
그 반대는 어떻습니까? not_camel_case에서 notCamelCase및 / 또는 NotCamelCase?로 변환
john2x

9
camel_Case를 변환 할 때 이중 밑줄을 피하려면 다음 행을 추가하십시오.s2.replace('__', '_')
Marcus Ahlberg

2
이것은 가역적이지 않습니다. getHTTPResponseCode는 get_h_t_t_p_response_code로 변환해야합니다. getHttpResponseCode는 get_http_response_code로 변환한다
K2xL

4
@AnmolSinghJaggi 첫 번째 정규 표현식은 머리 글자 뒤에 약어 (예 : "HTTPResponse"-> "HTTP_Response") 또는 대문자로 시작하는 대문자 (예 : "getResponse"-> ") get_Response ". 두 번째 정규 표현식은 두 약어가 아닌 일반적인 경우 (예 :"ResponseCode "->"Response_Code ")와 모든 소문자에 대한 최종 호출을 처리합니다. 따라서"getHTTPResponseCode "->"getHTTP_ResponseCode "->"get_HTTP_Response_Code "- > "get_http_response_code"
Jeff Moser

188

패키지 인덱스에는 이러한 것들을 처리 할 수 있는 변곡 라이브러리 가 있습니다. 이 경우 다음을 찾고 있습니다 inflection.underscore().

>>> inflection.underscore('CamelCase')
'camel_case'

44
이 작업을 수행하는 훌륭한 라이브러리가있을 때 사람들이 사용자 정의 함수 사용을 투표하는 이유를 이해하지 못합니다. 우리는 바퀴를 재발 명해서는 안됩니다.
oden

88
@oden 어쩌면 한 줄 함수의 작업을 수행하기 위해 완전히 새로운 의존성 을 추가하는 것이 깨지기 쉬운 과잉 기술 이기 때문에 어쩌면 ?
Cecil Curry

11
예를 들어, 과잉 상태인지 확인하십시오. 더 큰 응용 분야에서 휠을 재발 명하고 난독 화 할 필요가 없습니다.
Brad Koch

11
정규 표현식은 "단일 라인"으로 다시 되돌아 가기 때문에 적절한 테스트를 통해 둘 이상의 라인이 필요합니다.
studgeek

12
@CecilCurry : 당신이 훌륭한 프로그래머라고 확신하지만, 고려하지 않은 경우는 확실하지 않습니다. 여기에서 다른 답변을보십시오. 그렇기 때문에 항상 라이브러리를 선택하는 이유는 나보다 더 많은 개발자들의 총체적인 경험이기 때문입니다.
Michael Scheper

104

왜 이것들이 그렇게 복잡한 지 모르겠습니다.

대부분의 경우 간단한 표현으로 ([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'

ALLCap을 all_caps로 분리하고 문자열에서 숫자를 기대하려면 여전히 두 개의 개별 런을 수행 할 필요가 없습니다. |이 표현식 ((?<=[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'

그것은 모두 당신이 원하는 것에 달려 있으므로 지나치게 복잡해서는 안되므로 귀하의 요구에 가장 적합한 솔루션을 사용하십시오.

조이!


1
마지막 반복은 가장 영리한 IMO입니다. 각 단어의 시작 부분에서 단일 문자 만 교체한다는 점을 이해하는 데 약간의 시간이 걸렸습니다. 단지 접근 방식은 내가 생각해 낸 방식과 다르기 때문입니다. 잘 했어요
저스틴 밀러

2
나는 (?!^)룩-비하인드라는 표현 에 당황했다 . 내가 빠진 것이 아니라면, 여기서 실제로 원하는 것은로 표현되는 부정적인 모습 (?<!^)입니다. 당신의 부정적인 (?!^)
예견

7
이 잘 밑줄을 기존 처리하지 않습니다 "Camel2WARNING_Case_CASE"됩니다 "camel2_warning_case__case". 당신은 (?<!_)그것을 해결하기 위해 부정적인 lookbehind를 추가 할 수 있습니다 : re.sub('((?<=[a-z0-9])[A-Z]|(?!^)(?<!_)[A-Z](?=[a-z]))', r'_\1', "Camel2WARNING_Case_CASE").lower() returns 'camel2_warning_case_case'
luckydonald

@Apteryx 당신 말이 맞아서 (?!^)"뒤로보기"라고 잘못 불렸고 대신 부정적 예측 어설 션 이라고 불렀을 것 입니다. 이 멋진 설명에서 알 수 있듯이 , 부정적인 lookaheads는 일반적으로 찾고있는 표현 뒤에 옵니다. 따라서 (?!^)" 따르지 않는 ''곳을 찾으 <start of string>십시오" 라고 생각할 수 있습니다 . 실제로 부정적인 룩 백도 작동합니다. (?<!^)" 앞에 있지 않는 ''곳을 찾으십시오" 라고 생각할 수 있습니다 <start of string>.
Nathaniel Jones

17

stringcase 는 이것에 대한 나의 도서관입니다. 예 :

>>> from stringcase import pascalcase, snakecase
>>> snakecase('FooBarBaz')
'foo_bar_baz'
>>> pascalcase('foo_bar_baz')
'FooBarBaz'

11

개인적으로 파이썬에서 정규 표현식을 사용하는 것이 어떻게 우아하게 묘사 될 수 있는지 잘 모르겠습니다. 여기서 대부분의 답변은 "코드 골프"유형 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'

1
+=문자열에서 거의 항상 나쁜 생각입니다. 목록과 ''.join()끝에 추가하십시오. 또는이 경우에는 밑줄로 간단히 결합하십시오.
ThiefMaster

21
한 줄짜리 정규 표현식 은 비효율적 인 여러 줄 문자 반복 및 무차별 문자열 문합에 대해 거의 모든 실제적인 방식 (가독성 포함)에서 본질적으로 우월 하지 않습니까? Python은 이유에 따라 즉시 정규식 지원을 제공합니다.
Cecil Curry

1
@CecilCurry-정규 표현식은 매우 복잡합니다. Python이 사용하는 컴파일러 및 구문 분석기를 참조하십시오. svn.python.org/projects/python/trunk/Lib/sre_compile.py & svn.python.org/projects/python/trunk/Lib/sre_parse.py- 간단한 문자열 조작 이것은 RE를 사용하는 것보다 훨씬 빠릅니다.
Evan Borgstrom

1
+1. 정규식은 실제 CPU 싱크 일 수 있으며 집중적 인 계산에서는 성능이 크게 저하됩니다. 간단한 작업의 경우 항상 간단한 기능을 선호합니다.
Fabien

4
"간단한 작업의 경우 항상 간단한 기능을 선호합니다"는 확실히 좋은 조언이지만이 답변은 단순한 기능이나 우아한 기능이 아닙니다. 정규식 (즉는 또한 안된 오류의 많은 잠재적 포인트가) 완전히 조기 최적화이다 느려질 수 있지만,이 같은 복잡한 기능을 디폴트 수도
kevlarr

9

re가능 하면 피하는 것이 좋습니다.

def to_camelcase(s):
    return ''.join(['_' + c.lower() if c.isupper() else c for c in s]).lstrip('_')
>>> to_camelcase("ThisStringIsCamelCase")
'this_string_is_camel_case'

1
이것은 re라이브러리를 사용하지 않고 내장 str.methods 만 사용하여 한 줄로만 작업을 수행 하지 않는 가장 컴팩트 한 것입니다 ! 이 답변 과 비슷 하지만 if ... else잠재적으로 추가 된 "_"를 첫 문자로 제거 하여 슬라이싱 및 추가 를 사용하지 않습니다. 나는 이것을 가장 좋아한다.
콜리 디어

허용되는 답변 6.81 µs ± 22.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)이지만 2.51 µs ± 25.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)2.5x 배 빠른 이 응답의 경우 ! 이거 너무 좋아!
WBAR

8
''.join('_'+c.lower() if c.isupper() else c for c in "DeathToCamelCase").strip('_')
re.sub("(.)([A-Z])", r'\1_\2', 'DeathToCamelCase').lower()

7

이 솔루션이 이전 답변보다 더 간단하다고 생각합니다.

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

정규식은 세 가지 패턴과 일치합니다.

  1. [A-Z]?[a-z]+: 선택적으로 대문자로 시작하는 연속적인 소문자입니다.
  2. [A-Z]{2,}(?=[A-Z][a-z]|\d|\W|$): 대문자 두 개 이상의 연속 된 대문자. 마지막 대문자가 소문자 뒤에 오는 경우 lookahead를 사용하여 마지막 대문자를 제외합니다.
  3. \d+: 연속 번호.

을 사용하여 re.findall소문자로 변환하고 밑줄로 결합 할 수있는 개별 "단어"목록을 얻습니다.


1
여기에 Numerics를 독립적으로 토큰 화하는 좋은 예가 있습니다.
math_law

1
브로큰 : 변환 ( "AB") -> 'A'
ADW

5

왜 두 개의 .sub () 호출을 사용하는지 모르겠습니다. :) 나는 정규 표현식 전문가가 아니지만 특정 요구 사항에 적합한이 기능으로 단순화했습니다 .POST 요청에서 vars_with_underscore로 camelCasedVars를 변환하는 솔루션이 필요했습니다.

def myFunc(...):
  return re.sub('(.)([A-Z]{1})', r'\1_\2', "iTriedToWriteNicely").lower()

getHTTPResponse와 같은 이름으로 작동하지 않으므로 이름 지정 규칙이 잘못되었다고 들었습니다 (getHttpResponse와 비슷해야 함).이 양식을 훨씬 쉽게 암기 할 수 있습니다.


'{1}'은 (는) 필요하지 않지만 때로는 안개를 분명히하는 데 도움이됩니다.
desper4do

2
-1 : 작동하지 않습니다. 와 예를 들어와 시도 'HTTPConnectionFactory', 코드가 생성 'h_tt_pconnection_factory'허용 대답에서 코드를 생성,'http_connection_factory'
vartec

4

내 해결책은 다음과 같습니다.

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.


7
정규식을 사용하는 것과 비교할 때 매우 복잡하기 때문에 -1입니다.
Eric O Lebigot

7
EOL, 나는 많은 비정규 사람들이 다르게 생각할 것이라고 확신합니다.
Evan Fosmark

이 솔루션은 _Method, _test_Method , __test__Method, getHTTPrespnseCode, __get_HTTPresponseCode, _Camel_Case, _Test 및 _test_Method와 같은 경우에 실패합니다 .
freegnu

3
@Evan, 그 사람들은 나쁜 프로그래머 일 것입니다.
Jesse Dhillon

3

그것의 재미를 위해 :

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

3
ABCEF에서 Z 대신 c.isupper () ... Z
Jimmy

1
파이썬에는 정규 표현식이 없습니까? 빠른 's / [az] \ K ([AZ] [az]) / _ \ L $ 1 / g; 펄의 lc $ _ '가 작업을 수행합니다 (getHTTPResponseCode를 잘 처리하지는 않지만 getHttpResponseCode라는 이름이 필요합니다)
jrockway

5
str.join를 위해 사용되지 않습니다 나이 . ''.join(..)대신 사용하십시오 .
John Fouhy

jrockway : "re"모듈을 통해 정규 표현식이 있습니다. 여기에 게시 된 접근법보다는 정규식을 사용 하여이 작업을 수행하는 것이 너무 어렵지 않아야합니다.
Matthew Iselin

파이썬 멍청한 놈이지만 왜 str.join ( '', output)을 반환합니까? 사본을 만들려면?
Tarks

3

정규식을 사용하는 것이 가장 짧을 수 있지만이 솔루션은 더 읽기 쉽습니다.

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

@blueyed 그것은 완전히 무관합니다.이 질문은 django와 관련이 없습니다.
3k-

HTTPResponseCode와 같은 예제 일 뿐이며 stackoverflow.com/a/23561109/15690의해 처리됩니다 .
blueyed

3

너무 많은 복잡한 방법 ... "Titled"그룹을 모두 찾아서 소문자 변형을 밑줄로 결합하십시오.

>>> 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]*)마스크 를 사용할 수 있습니다 .



2

이것은 우아한 방법이 아니며 간단한 상태 머신 (비트 필드 상태 머신)의 매우 '낮은 레벨'구현입니다.이를 해결하기 위해 가장 안티 파이 토닉 모드이지만 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와 같은 모든 케이스 유형을 구문 분석 할 수 있습니다.

도움이 되길 바랍니다.


1
끔찍하지만 내 컴퓨터의 정규식보다 약 3 배 빠릅니다. :)
jdiaz5513


1

훌륭한 Schematics 라이브러리를 살펴보십시오

https://github.com/schematics/schematics

파이썬에서 자바 스크립트 풍미로 직렬화 / 직렬화 할 수있는 형식화 된 데이터 구조를 만들 수 있습니다. 예 :

class MapPrice(Model):
    price_before_vat = DecimalType(serialized_name='priceBeforeVat')
    vat_rate = DecimalType(serialized_name='vatRate')
    vat = DecimalType()
    total_price = DecimalType(serialized_name='totalPrice')

1

이 간단한 방법으로 작업을 수행해야합니다.

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()
  • 우리는 대문자 (또는 0)의 대문자가 뒤 따르고 그 뒤에 소문자가 나오는 대문자를 찾습니다.
  • 밑줄은 그룹에서 찾은 마지막 대문자가 나타나기 직전에 배치되며 다른 대문자가 앞에 오는 경우 대문자 앞에 놓일 수 있습니다.
  • 밑줄이 있으면 제거하십시오.
  • 마지막으로 전체 결과 문자열이 소문자로 변경됩니다.

( 여기 에서 가져온 온라인 작업 예제 참조 )


이는 반대 질문 (어떻게 변환하기위한 해답 낙타 경우).
저스틴

1

와우 방금이 코드를 장고 스 니펫에서 훔쳤습니다. 심판 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'

정규식 데모


1
str을 로컬 변수 이름으로 사용하는 형식이 잘못되었습니다.
freegnu

문자열의 시작 또는 끝에 밑줄이 있고 대문자 앞에 밑줄이 있으면 비참하게 실패합니다.
freegnu

번호를 고려하지 않습니다 😬
villy393

0

정규 표현식을 사용하는 끔찍한 예 ( 이를 쉽게 정리 할 수 있습니다 :)) :

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

편집 : 밑줄이 무조건 삽입되기 때문에 "Test"와 같은 경우에 개선의 여지가 있음을 쉽게 알 수 있습니다.


0

탭으로 구분 된 파일에서 헤더를 변경하기 위해 수행 한 작업은 다음과 같습니다. 파일의 첫 번째 줄만 편집 한 부분을 생략하고 있습니다. re 라이브러리를 사용하여 파이썬에 쉽게 적응시킬 수 있습니다. 여기에는 숫자 분리도 포함되지만 숫자는 함께 유지됩니다. 줄이나 탭의 시작 부분에 밑줄을 넣지 말라고하는 것보다 쉬웠 기 때문에 두 단계로 수행했습니다.

1 단계 ... 대문자 또는 정수 앞에 소문자를 붙여 밑줄을 붙입니다.

검색:

([a-z]+)([A-Z]|[0-9]+)

바꿔 놓음:

\1_\l\2/

2 단계 ... 위를 취하고 다시 실행하여 모든 대문자를 소문자로 변환하십시오.

검색:

([A-Z])

교체 (백 슬래시, 소문자 L, 백 슬래시 중 하나) :

\l\1

0

나는 체인이 필요하다는 것을 제외하고는 같은 문제에 대한 해결책을 찾고 있었다. 예 :

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

물론 다른 솔루션에서 설명한대로 정규식을 미리 컴파일하거나 하이픈 대신 밑줄로 조인 할 수 있습니다.


0

정규 표현식없이 간결하지만 HTTPResponseCode => 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())])

0

라이브러리없이 :

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

0

이 사이트에서 제안 된 아주 멋진 RegEx :

(?<!^)(?=[A-Z])

파이썬에 String Split 메소드가 있다면 작동해야합니다 ...

자바에서 :

String s = "loremIpsum";
words = s.split("(?&#60;!^)(?=[A-Z])");

불행히도, 파이썬 정규 표현식 모듈은 (버전 3.6 기준) 길이가 0 인 일치 분할을 지원하지 않습니다.
rspeed

0
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()

0

누군가가 완전한 소스 파일을 변환 해야하는 경우를 대비하여 스크립트를 작성하십시오.

# 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))

-1

나는 이것으로 꽤 운이 좋았습니다.

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)

-1
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()

-3

사용 : str.capitalize()변수 str에 포함 된 문자열의 첫 문자를 대문자로 변환하고 전체 문자열을 반환합니다.

예 : 명령 : "hello".capitalize () 출력 : Hello


이것은 질문과 관련이 없습니다-OP는 CamelCase를 원합니다-> snake_case, 대문자는 아닙니다.
브래드 코흐
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.