CamelCase'i snake_case'e dönüştürmek için zarif Python işlevi?


333

Misal:

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

28
Diğer yöne dönüştürmek için, bu diğer yığın akışı sorusuna bakın.
Nathan

10
nb bu NotCamelCaseamathisIs
Matt Richards

5
@MattRichards Bu bir tartışma konusudur. wiki
NO_NAME

@MattRichards Örneğin Java'da her ikisini de kullanırlar, CamelCase Sınıf tanımlarını adlandırırken kullanılır, camelCase ise başlatılmış değişkenleri adlandırırken kullanılır.
darkless

Yanıtlar:


797

Deve kılıfı - Yılan çantası

import re

name = 'CamelCaseName'
name = re.sub(r'(?<!^)(?=[A-Z])', '_', name).lower()
print(name)  # camel_case_name

Bunu birçok kez yaparsanız ve yukarıdakiler yavaşsa, normal ifadeyi önceden derleyin:

pattern = re.compile(r'(?<!^)(?=[A-Z])')
name = pattern.sub('_', name).lower()

Daha gelişmiş vakaları özel olarak ele almak için (bu artık geri döndürülemez):

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

Yılan çantası - deve çantası

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

1
Bu çözüm şu durumlarda başarısız olur: _test_Method, __test__Method, _Test, getHTTPresponseCode, __CamelCase ve _Camel_Case.
freegnu

6
tersine ne dersin? Bir dönüştürme not_camel_caseiçin notCamelCaseve / veya NotCamelCase?
john2x

9
Örneğin camel_Case'i dönüştürürken çift alt çizgiden kaçınmak için bu satırı ekleyin:s2.replace('__', '_')
Marcus Ahlberg

2
Bunun çok geri dönüşümlü olmadığını unutmayın. getHTTPResponseCode, get_h_t_t_p_response_code biçimine dönüştürmelidir. getHttpResponseCode, get_http_response_code
K2xL

4
@AnmolSinghJaggi İlk normal ifade, bir kısaltmanın kenar harfini ve ardından başka bir kelimeyi (örn. "HTTPResponse" -> "HTTP_Response") VEYA daha küçük harfli bir sözcüğün ardından gelen büyük harf (normalde "getResponse" -> " İkinci normal ifade, iki kısaltma olmayan normal durumu (örn. "ResponseCode" -> "Response_Code") ve ardından her şeyi küçük harfe çevirmek için son çağrıyı işler. Böylece "getHTTPResponseCode" -> "getHTTP_ResponseCode" -> "get_HTTP_Response_Code" - > "get_http_response_code"
Jeff Moser

188

Paket dizininde bunları sizin için halledebilecek bir çekim kütüphanesi var. Bu durumda, şunları arıyorsunuz inflection.underscore():

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

44
Bu görevi yerine getiren harika bir kütüphane olduğunda insanların neden özel işlevlerin kullanımına oy verdiğini anlamıyorum. Tekerleği yeniden icat etmemeliyiz.
oden

88
@oden Belki de tek satırlık bir işlevin işini yapmak için yeni bir bağımlılık eklemek kırılgan bir aşırı öldürme olabilir?
Cecil Curry

11
Bir örnek olarak, aşırıya kaçmış olduğundan emin olun. Daha büyük bir uygulamada, tekerleği yeniden icat etmeye ve şaşırtmaya gerek yoktur.
Brad Koch

11
Normal ifadeler "tek bir satıra" geri döndü, bu yüzden uygun testlerle birden fazla satır var.
studgeek

12
@CecilCurry: Harika bir programcı olduğunuzdan eminim, ancak dikkate almadığınız durumlar olmadığından emin değilim; örnekler için diğer yanıtlara bakın. Bu yüzden her zaman bir kütüphane seçeceğim, çünkü bu benden çok daha fazla geliştiricinin toplam deneyimi.
Michael Scheper

104

Bunların neden bu kadar karmaşık olduğunu bilmiyorum.

çoğu durumda, basit ifade ([A-Z]+)hile yapacak

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

İlk karakteri görmezden gelmek için arkasına bak (?!^)

>>> 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'i all_caps'a ayırmak ve dizenizdeki sayıları beklemek istiyorsanız, yine de iki ayrı çalışma yapmanız gerekmez Sadece |bu ifade ((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))kitaptaki hemen hemen her senaryoyu işleyebilir

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

Her şey ne istediğinize bağlıdır, bu yüzden aşırı karmaşık olmamalı, ihtiyaçlarınıza en uygun çözümü kullanın.

Njoy!


1
Son yineleme en akıllı IMO'dur. Her kelimenin başlangıcında tek bir karakterin yerini aldığını anlamak biraz zamanımı aldı - ve bu sadece yaklaşımın kendimle ortaya çıkacağımdan farklı olmasıydı. Güzel yapılmış.
Justin Miller

2
(?!^)Arkasına bakma denilen ifadeden şaşkındım . Bir şeyi kaçırmadıkça, burada gerçekten istediğimiz şey, olarak ifade edilmesi gereken olumsuz bir bakış (?<!^). Olumsuz bakış (?!^)
açınızı

7
Bu, önceden var olan alt çizgileri iyi işlemez: "Camel2WARNING_Case_CASE"olur "camel2_warning_case__case". Bunu (?<!_)çözmek için negatif bir re.sub('((?<=[a-z0-9])[A-Z]|(?!^)(?<!_)[A-Z](?=[a-z]))', r'_\1', "Camel2WARNING_Case_CASE").lower()'camel2_warning_case_case'
görüş arkası

@Apteryx Haklısın, (?!^)yanlış bir şekilde "arkasına bak" olarak adlandırıldı ve bunun yerine negatif bir ileri görüş iddiası olarak adlandırılmalıydı . Gibi bu güzel açıklama gösterileri, negatif lookaheads genellikle gelip sonra ifadesi için sen arama. Yani aklınıza gelebilecek (?!^)"bulmak olarak ''nerede <start of string>takip etmez". Gerçekten de, olumsuz da geriye bakan çalışır: aklınıza gelebilecek (?<!^)"buldukça ''nerede <start of string>değil Precede yok".
Nathaniel Jones

17

stringcase benim bunun için benim kütüphane olduğunu; Örneğin:

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

11

Şahsen python'da düzenli ifadeler kullanan bir şeyin nasıl zarif olarak tanımlanabileceğinden emin değilim. Çoğu cevap sadece "kod golf" tipi RE hileler yapıyor. Zarif kodlamanın kolayca anlaşılması gerekiyor.

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
+=iplerde neredeyse her zaman kötü bir fikirdir. Bir listeye ekleyin ''.join()ve sonunda listeye ekleyin . Veya bu durumda, sadece bir alt çizgi ile katılın ...
ThiefMaster

21
Tek satırlık düzenli bir ifade , verimsiz çok satırlı karakter yinelemesine ve kaba kuvvet telli munging'e neredeyse her pratik yoldan (okunabilirlik dahil) nasıl daha üstün değildir ? Python, bir sebepten ötürü kullanıma hazır düzenli ifade desteği sağlar.
Cecil Curry

1
@CecilCurry - Düzenli ifadeler ÇOK karmaşıktır. Python'un kullandığı derleyiciye ve ayrıştırıcıya bakın: svn.python.org/projects/python/trunk/Lib/sre_compile.py & svn.python.org/projects/python/trunk/Lib/sre_parse.py - Basit dize düzenleme bu muhtemelen aynı şeyi yapan bir RE'den daha hızlıdır.
Evan Borgstrom

1
+1. Regexes gerçek bir CPU lavabo olabilir ve yoğun hesaplamalarda performanslarınızı önemli ölçüde azaltacaktır. Basit görevler için her zaman basit işlevleri tercih edin.
Fabien

4
"Basit görevler için, her zaman basit işlevleri tercih edin" kesinlikle iyi bir tavsiye, ancak bu cevap ne basit bir işlev ne de zarif bir işlevdir. Regex daha yavaş olabilir, ancak böyle karmaşık bir işlevi varsayılan olarak (aynı zamanda test edilmemiştir ve çok sayıda potansiyel hata noktasına sahiptir) tamamen erken optimizasyondur
kevlarr

9

reMümkünse kaçınmayı tercih ederim :

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
Bu, rekütüphaneyi kullanmaktan ve sadece yerleşik satır yöntemlerini kullanarak bir satırda bir şeyler yapmaktan kaçınan en kompakt olanıdır! Bu cevaba benzer , ancak if ... elsepotansiyel olarak eklenen "_" karakterini ilk karakter olarak sıyırarak dilimleme ve ilave kullanmaktan kaçınır . Bunu en çok seviyorum.
colidyre

Kabul edilen cevap için 6.81 µs ± 22.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)ama bu cevap 2.51 µs ± 25.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)için 2,5 kat daha hızlı! Bunu sev!
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

Bu çözümün önceki yanıtlardan daha basit olduğunu düşünüyorum:

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

Hangi çıktılar:

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

Normal ifade üç kalıpla eşleşir:

  1. [A-Z]?[a-z]+: İsteğe bağlı olarak büyük harfle başlayan ardışık küçük harfler.
  2. [A-Z]{2,}(?=[A-Z][a-z]|\d|\W|$): İki veya daha fazla ardışık büyük harf. Sonrasında büyük harf olan küçük harfin ardından gelen büyük harfleri hariç tutmak için bir ileriye bakar.
  3. \d+: Ardışık sayılar.

Kullanarak re.findall, küçük harfe dönüştürülebilen ve alt çizgi ile birleştirilebilen tek tek "kelimelerin" bir listesini alırız.


1
Burada Numerics'i bağımsız olarak tokenize etmek için iyi bir örnek var.
math_law

1
Bozuk: dönüştürmek ("aB") -> 'a'
adw

5

Neden her iki .sub () çağrılarını kullanarak fikrim yok? :) Ben regex guru değilim, ama bazı ihtiyaçları için uygun olan bu fonksiyon basitleştirilmiş, ben sadece POST isteği vars_with_underscore için camelCasedVars dönüştürmek için bir çözüm gerekli:

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

GetHTTPResponse gibi isimlerle çalışmaz, çünkü kötü adlandırma kuralı olduğunu duydum (getHttpResponse gibi olmalı, açıkçası, bu formu ezberlemek çok daha kolay).


'{1}' in gerekli olmadığını söylemeyi unuttum, ancak bazen biraz sisi açıklığa kavuşturmaya yardımcı oluyor.
desper4do

2
-1: bu işe yaramıyor. İle örneğin ile deneyin 'HTTPConnectionFactory', kodunuz üreten 'h_tt_pconnection_factory'kabul edilen cevabını kod üretir,'http_connection_factory'
vartec

4

İşte benim çözümüm:

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)

Yorumlarda tartışılan köşe davalarını destekler. Örneğin, dönüştürmek gerekir getHTTPResponseCodeiçin get_http_response_codeolması gerektiği gibi.


7
-1 çünkü regexps kullanmaya kıyasla çok karmaşık.
Eric O Lebigot

7
EOL, eminim ki düzenli olmayan pek çok insan aksini düşünür.
Evan Fosmark

Bu çözüm şu durumlarda başarısız olur: _Method, _test_Method , __test__Method, getHTTPrespnseCode, __get_HTTPresponseCode, _Camel_Case, _Test ve _test_Method.
freegnu

3
@Evan, bu insanlar kötü programcılar olurdu.
Jesse Dhillon

3

Eğlenmek için:

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

Veya eğlenmek için daha fazlası:

>>> 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'de c yerine c.isupper () ... Z
Jimmy

1
Python'un normal ifadeleri yok mu? Hızlı 's / [az] \ K ([AZ] [az]) / _ \ L $ 1 / g; Perl'deki lc $ _ 'işi yapıyor (getHTTPResponseCode'u iyi işleyemese de; bu beklenen, getHttpResponseCode olarak adlandırılması bekleniyor)
jrockway

5
str.joinçağlar boyunca kullanımdan kaldırıldı . ''.join(..)Bunun yerine kullanın .
John Fouhy

jrockway: "re" modülü üzerinden düzenli ifadeleri vardır. Bu işi burada açıklanan yaklaşımlar yerine normal ifade kullanarak yapmak çok zor olmamalı.
Matthew Iselin

Python noob burada, ama neden dönüş str.join ('', çıktı)? Sadece bir kopya oluşturmak mı?
Tarks

3

Regexes kullanmak en kısa olabilir, ancak bu çözüm çok daha okunabilir:

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 tamamen ilgisiz, bu sorunun django ile ilgisi yok.
3k-

Bu, stackoverflow.com/a/23561109/15690 tarafından yönetilen HTTPResponseCode gibi bir örnektir .
blueyed

3

Çok karmaşık yöntemler ... Sadece tüm "Başlıklı" grubunu bulun ve alt kasalı varyantını alt çizgi ile birleştirin.

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

Grubun ilk karakteri veya ayrı bir grup gibi sayılar yapmak istemiyorsanız ([A-z][a-z0-9]*)maske kullanabilirsiniz .



2

Bu zarif bir yöntem değil, basit bir durum makinesinin (bitfield durum makinesi) çok 'düşük seviyeli' bir uygulamasıdır, muhtemelen bunu çözmek için en anti pitonik moddur, ancak yeniden modül de bu basitliği çözmek için çok karmaşık bir durum makinesi uygular görev, bu yüzden bu iyi bir çözüm olduğunu düşünüyorum.

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 tüm vaka tiplerini ayrıştırabilir: UpperSEQUENCEInterleaved, under_score, BIG_SYMBOLS ve cammelCasedMethods

Umarım faydalı olur


1
İğrenç, ama makinemdeki normal ifade yönteminden yaklaşık 3 kat daha hızlı çalışıyor. :)
jdiaz5513


1

Mükemmel Schematics lib'ine bir göz atın

https://github.com/schematics/schematics

Python'dan Javascript lezzetine seri hale getirebilen / serisini kaldırabilecek yazılı veri yapıları oluşturmanıza olanak tanır, örneğin:

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

Bu basit yöntem işi yapmalıdır:

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()
  • Herhangi bir sayıda (veya sıfır) büyük harfle başlayan ve ardından herhangi bir sayıda küçük harf içeren büyük harfler ararız.
  • Bir alt çizgi, grupta bulunan son büyük harfin ortaya çıkmasından hemen önce yerleştirilir ve bir tanesi, diğer büyük harflerden önce olması durumunda bu büyük harfin önüne yerleştirilebilir.
  • Sondaki alt çizgi varsa, bunları kaldırın.
  • Son olarak, sonuç dizesinin tamamı küçük harfe dönüştürülür.

( buradan alınır, çevrimiçi çalışma örneğine bakın )


Bu zıt soru (nasıl dönüştürmek için bir cevaptır için deve durumda).
Justin

1

Vay be bunu sadece django parçacıklarından çaldım. ref http://djangosnippets.org/snippets/585/

Oldukça zarif

camelcase_to_underscore = lambda str: re.sub(r'(?<=[a-z])[A-Z]|[A-Z](?=[^A-Z])', r'_\g<0>', str).lower().strip('_')

Misal:

camelcase_to_underscore('ThisUser')

İadeler:

'this_user'

REGEX DEMO


1
Yerel değişken adı olarak str kullanan bozuk form.
freegnu

Bir dizenin başında veya sonunda alt çizgi varsa ve büyük harflerden önce alt çizgi varsa, bu durum başarısız olur.
freegnu

sayıları dikkate almaz 😬
villy393

0

Düzenli ifadeler kullanan korkunç bir örnek (bunu kolayca temizleyebilirsiniz :)):

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

Gerçi getHTTPResponseCode için çalışıyor!

Alternatif olarak, lambda kullanarak:

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: "Test" gibi durumlarda iyileştirilmesi için yer olduğunu görmek oldukça kolay olmalıdır, çünkü alt çizgi koşulsuz eklenir.


0

Sekmeyle ayrılmış bir dosyadaki başlıkları değiştirmek için yaptığım bir şey. Dosyanın sadece ilk satırını düzenlediğim bölümü atlıyorum. Yeniden kütüphaneyle Python'a kolayca adapte edebilirsiniz. Bu aynı zamanda sayıları ayırmayı da içerir (ancak rakamları bir arada tutar). İki adımda yaptım çünkü bir satırın veya sekmenin başına bir alt çizgi koymamayı söylemekten daha kolaydı.

Birinci Adım ... büyük harflerle başlayan büyük harfleri veya tam sayıları bulun ve önüne bir alt çizgi ekleyin:

Arama:

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

Değiştirme:

\1_\l\2/

İkinci Adım ... Yukarıdakileri alın ve tüm harfleri küçük harfe dönüştürmek için tekrar çalıştırın:

Arama:

([A-Z])

Değiştirme (ters eğik çizgi, küçük L, ters eğik çizgi, bir):

\l\1

0

Aynı soruna bir çözüm arıyordum, ancak bir zincire ihtiyacım vardı; Örneğin

"CamelCamelCamelCase" -> "Camel-camel-camel-case"

Buradaki iki kelimelik güzel çözümlerden başlayarak aşağıdakileri buldum:

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

Karmaşık mantığın çoğu, ilk kelimeyi küçük harflerden kaçınmaktır. İlk kelimeyi değiştirmenin sakıncası yoksa daha basit bir sürüm:

"-".join(x.group(1).lower() for x in re.finditer("(^[^A-Z]+|[A-Z][^A-Z]+)", "stringToSplit"))

Elbette, diğer çözümlerde tartışıldığı gibi normal ifadeleri önceden derleyebilir veya kısa çizgi yerine alt çizgi ile birleştirebilirsiniz.


0

Düzenli ifadeler olmadan, ancak 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

Herhangi bir kütüphane olmadan:

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('__','_')

Biraz ağır ama

CamelCamelCamelCase ->  camel_camel_camel_case
HTTPRequest         ->  http_request
GetHTTPRequest      ->  get_http_request
getHTTPRequest      ->  get_http_request

0

Bu sitede önerilen çok güzel RegEx :

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

Python bir String Split yöntemi varsa, çalışması gerekir ...

Java dilinde:

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

Ne yazık ki, Python düzenli ifade modülü (sürüm 3.6'dan itibaren) sıfır uzunluklu eşleşmelerde bölmeyi desteklemez.
17'de 2

0
def convert(name):
    return reduce(
        lambda x, y: x + ('_' if y.isupper() else '') + y, 
        name
    ).lower()

Ve zaten devesiz girişi olan bir vakayı kapsamamız gerekirse:

def convert(name):
    return reduce(
        lambda x, y: x + ('_' if y.isupper() and not x.endswith('_') else '') + y, 
        name
    ).lower()

0

Birisinin tam bir kaynak dosyasını dönüştürmesi gerektiğinde, işte bunu yapacak bir komut dosyası vardır.

# 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

Bu ile oldukça iyi şanslar oldu:

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)

Bu tabii ki hız için bir optimize edilebilecek minik İstersen biraz.

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()Dizesinin ilk harfini (str değişkeninde bulunur) büyük harfe dönüştürmek ve dizenin tamamını döndürmek için kullanın.

Örnek: Komut: "merhaba" .capitalize () Çıktı: Merhaba


Bu şu soru ile ilgili değil - OP CamelCase istiyor -> snake_case, Büyük harf kullanımı değil.
Brad Koch
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.