Елегантна функція Python для перетворення CamelCase в snake_case?


333

Приклад:

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

28
Щоб конвертувати в інший бік, перегляньте це інше запитання про stackoverflow.
Натан

10
nb that NotCamelCasebut butthisIs
Matt Richards

5
@MattRichards Це питання спірне. wiki
NO_NAME

@MattRichards Наприклад, у Java вони використовують обидва, CamelCase використовується для іменування визначень класу, тоді як camelCase використовується для іменування ініціалізованих змінних.
безтемний

Відповіді:


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.
фрігну

6
як щодо реверсу? Перетворити a 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"
Джефф Мозер,

188

В індексі пакунків є бібліотека флексій, яка може обробляти ці речі за вас. У цьому випадку ви шукаєте inflection.underscore():

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

44
Я не розумію, чому люди голосують за використання спеціальних функцій, коли є велика бібліотека, яка виконує це завдання. Ми не повинні винаходити колесо.
Оден

88
@oden Можливо, тому, що додавання нової залежності для виконання однолінійної функції є крихким надмірним вбивством?
Сесіль Карі

11
Для одного випадку впевнений, що це надмірно. Завдяки більшому застосуванню, не потрібно винаходити та придушувати колесо.
Бред Кох

11
Regexes багато повернувся в "єдину лінію", тому це набагато більше, ніж один рядок при належному тестуванні.
studgeek

12
@CecilCurry: Я впевнений, що ти чудовий програміст, але я не впевнений, що не буває випадків, які ти не розглядав - просто подивись інші відповіді тут на приклади. Тому я завжди вибираю бібліотеку, бо це сумарний досвід набагато більше дияволів, ніж я.
Майкл Шепер

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'

Якщо ви хочете розділити ALLCaps на 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'

Все залежить від того, що ви хочете, тому використовуйте рішення, яке найкраще відповідає вашим потребам, оскільки воно не повинно бути надмірно складним.

nJoy!


1
Остання ітерація - найрозумніша, ІМО. Мені потрібно було трохи зрозуміти, що це замінює лише один символ на початку кожного слова - і це було лише тому, що підхід був іншим, ніж той, який я придумав би сам. Чудово зроблено.
Джастін Міллер

2
Мене спантеличив (?!^)вираз, який називався оглядом. Якщо я чогось не пропускаю, те, що ми справді хочемо тут, - це негативний погляд, який слід виражати як (?<!^). З причин, я не можу зрозуміти ваш негативний погляд вперед, (?!^)здається, теж працює
Apteryx

7
Це не справляється з попередньо існуючими підкресленнями: "Camel2WARNING_Case_CASE"стає "camel2_warning_case__case". Ви можете додати (?<!_)негативний re.sub('((?<=[a-z0-9])[A-Z]|(?!^)(?<!_)[A-Z](?=[a-z]))', r'_\1', "Camel2WARNING_Case_CASE").lower()'camel2_warning_case_case'
погляд ззаду

@Apteryx Ви маєте рацію, (?!^)неправильно називали "погляд позаду", і натомість слід було б називати негативним твердженням пошуку . Як показує це приємне пояснення , негативні пошукові запити зазвичай виникають після виразу, який ви шукаєте. Тож можна подумати (?!^)як «знайти ''там, де <start of string>не слідує». Дійсно, негативний погляд ззаду також працює: ви можете вважати (?<!^)"знайти ''там, де <start of string>не передує".
Натаніель Джонс

17

stringcase - це моя перехідна бібліотека для цього; наприклад:

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

11

Особисто я не впевнений, як все, що використовує регулярні вирази в python, можна охарактеризувати як елегантне. Більшість відповідей тут просто виконує трюки типу «кодовий гольф». Елегантне кодування передбачається легко зрозуміти.

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()в кінці. Або в цьому випадку просто
з'єднайте

21
Як однорядковий регулярний вираз не є надмірно кращим практично у кожному практичному способі (включаючи читаність) неефективній багаторядковій ітерації символів та зміні рядкової грубої сили? Python забезпечує регулярну підтримку виразів поза межами коробки з причини.
Сесіль Карі

1
@CecilCurry - Регулярні вирази ДУЖЕ складні. Перегляньте компілятор і аналізатор, який Python використовує: svn.python.org/projects/python/trunk/Lib/sre_compile.py & svn.python.org/projects/python/trunk/Lib/sre_parse.py - Просте маніпулювання рядками, наприклад це, ймовірно, набагато швидше, ніж РЕ робить те ж саме.
Еван Боргстром

1
+1. Regexes можуть бути справжньою раковиною процесора, а за інтенсивних розрахунків різко знизяться ваші показники. Для простих завдань завжди віддайте перевагу простим функціям.
Fabien

4
"Для простих завдань завжди віддайте перевагу простим функціям", безумовно, хороша порада, але ця відповідь не є ні простою функцією, ні елегантною. Regex може бути повільнішим, але дефолт до такої складної функції, як ця (тобто ТАКОЖ не перевірена і має численні потенційні моменти помилок) є повністю передчасною оптимізацією
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,5 рази швидша! Люблю це!
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
Тут є хороший приклад, щоб отримати чисельні токенізовані самостійно.
math_law

1
Broken: convert ("aB") -> 'a'
adw

5

Я не розумію, чому використовувати обидва .sub () дзвінки? :) Я не регекс-гуру, але я спростив функцію до цього, який підходить для моїх певних потреб, мені просто потрібно було рішення перетворити camelCasedVars з POST-запиту на vars_with_underscore:

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 тому, що це дуже складно порівняно з використанням регулярних виразів.
Ерік О Лебігот

7
EOL, я впевнений, що багато людей, які не переростають, подумають інакше.
Еван Фосмарк

Це рішення виходить з ладу в таких випадках: _Method, _test_Method , __test__Method, getHTTPrespnseCode, __get_HTTPresponseCode, _Camel_Case, _Test та _test_Method.
freegnu

3
@Evan, ці люди були б поганими програмістами.
Джессі Діллон

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
c.isupper (), а не c в ABCEF ... Z
Джиммі

1
У Python немає регексів? Швидкий s / [az] \ K ([AZ] [az]) / _ \ L $ 1 / g; lc $ _ 'в Perl виконує цю роботу (хоча вона не обробляє getHTTPResponseCode добре; але, як очікується, її слід назвати getHttpResponseCode)
jrockway

5
str.joinбула застаріла протягом століть . Використовуйте ''.join(..)замість цього.
Джон Фугі

jrockway: Він має регулярні вирази, через модуль "re". Ця робота не повинна бути надто складною, використовуючи регулярний вираз, а не підходи, розміщені тут.
Матвій Іселін

Тут Python noob, але навіщо повертати str.join ('', output)? Просто для створення копії?
Завдання

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.
к.

Це просто приклад, як HTTPResponseCode, який обробляється stackoverflow.com/a/23561109/15690 .
синенький

3

Стільки складних методів ... Просто знайдіть усю групу "Звання" та приєднайте її нижній регістр із підкресленням.

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

Це не елегантний метод, це дуже «низький рівень» реалізації простої державної машини (бітфілд-стан машини), можливо, найбільш антипітонічний режим для вирішення цього питання, однак повторний модуль також реалізує занадто складну машину для вирішення цього простого завдання, тому я думаю, що це хороше рішення.

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

Це дозволяє створювати типізовані структури даних, які можуть серіалізувати / десеріалізувати з 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')

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()
  • Ми шукаємо великі літери, яким передує будь-яка кількість (або нуль) великих літер, а за ними будь-яка кількість малих літер.
  • Підкреслення розміщується безпосередньо перед появою останньої великої літери, знайденої в групі, і може бути поставлена ​​перед цією великою літерою, якщо їй передують інші великі літери.
  • Якщо є задні підкреслення, видаліть їх.
  • Нарешті, весь рядок результатів змінюється на малі регістри.

(взято звідси , див. робочий приклад в Інтернеті )


Це відповідь на протилежне запитання (як перетворити на випадок верблюда).
Джастін

1

Нічого, я просто вкрав це з фрагментів джанго. 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'

REGEX DEMO


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

EDIT: Також слід досить легко побачити, що є місце для вдосконалення для таких випадків, як "Тест", оскільки підкреслення вставлено беззастережно.


0

Ось що я зробив, щоб змінити заголовки у файлі з обмеженими вкладками. Я опускаю частину, де я редагував лише перший рядок файлу. Ви можете досить легко адаптувати його до Python за допомогою бібліотеки. Це також включає відокремлення чисел (але зберігає цифри разом). Я зробив це в два кроки, тому що це було простіше, ніж сказати йому не ставити підкреслення на початку рядка чи вкладки.

Перший крок ... знайдіть великі літери або цілі числа, які передують маленьким літерам, і передуйте їх підкресленням:

Пошук:

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

Заміна:

\1_\l\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])

Якщо у python є метод String Split, він повинен працювати ...

На Java:

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

На жаль, модуль регулярного вираження Python не підтримує (за версією 3.6) розбиття на відповідність нульовій довжині.
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) у велику літеру та повертає всю рядок.

Приклад: Команда: "привіт" .capitalize () Вихід: Привіт


Це не пов’язано з питанням - ОП хоче CamelCase -> snake_case, а не з великої літери.
Бред Кох
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.