Hàm Python thanh lịch để chuyển đổi CamelCase thành Snake_case?


333

Thí dụ:

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

28
Để chuyển đổi theo hướng khác, hãy xem câu hỏi stackoverflow khác này .
Nathan

10
nb đó là NotCamelCasenhưngthisIs
Matt Richards

5
@MattRichards Đó là vấn đề tranh chấp. wiki
NO_NAME

@MattRichards Ví dụ trong Java họ sử dụng cả hai, CamelCase được sử dụng để đặt tên các định nghĩa Class, trong khi camelCase được sử dụng để đặt tên các biến khởi tạo.
tối

Câu trả lời:


796

Trường hợp lạc đà đến trường hợp rắn

import re

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

Nếu bạn làm điều này nhiều lần và ở trên chậm, hãy biên dịch regex trước:

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

Để xử lý các trường hợp nâng cao hơn đặc biệt (điều này không thể đảo ngược được nữa):

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

Trường hợp rắn để lạc đà

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

1
Giải pháp này thất bại trong các trường hợp này: _test_Method, __test__Method, _Test, getHTTPresponseCode, __CamelCase và _Camel_Case.
freegnu

6
Làm thế nào về ngược lại? Chuyển đổi một not_camel_caseđể notCamelCasevà / hoặc NotCamelCase?
john2x

9
Để tránh nhân đôi dấu gạch dưới khi chuyển đổi, ví dụ camel_Case, hãy thêm dòng này:s2.replace('__', '_')
Marcus Ahlberg

2
Lưu ý điều này là không thể đảo ngược. getHTTPResponseCode nên chuyển đổi thành get_h_t_t_p_response_code. getHttpResponseCode nên chuyển đổi thành get_http_response_code
K2xL

4
Tài khoản get_Response ". Regex thứ hai xử lý trường hợp bình thường của hai từ không viết tắt (ví dụ:" FeedbackCode "->" Feedback_Code ") theo sau là một lệnh gọi cuối cùng để viết thường mọi thứ. > "get_http_response_code"
Jeff Moser

188

Có một thư viện uốn trong chỉ mục gói có thể xử lý những thứ này cho bạn. Trong trường hợp này, bạn sẽ tìm kiếm inflection.underscore():

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

44
Tôi không hiểu tại sao mọi người lại bỏ phiếu sử dụng các chức năng tùy chỉnh khi có một thư viện tuyệt vời thực hiện nhiệm vụ này. Chúng ta không nên phát minh lại bánh xe.
oden

87
@oden Có lẽ bởi vì việc thêm toàn bộ phụ thuộc mới để thực hiện công việc của một hàm đơn là dễ bị giết quá mức?
Cecil Curry

11
Ví dụ, chắc chắn đó là quá mức cần thiết. Trên một ứng dụng lớn hơn, không cần phải phát minh lại và làm xáo trộn bánh xe.
Brad Koch

11
Regexes lại rất nhiều thành một "dòng duy nhất", đó là lý do tại sao nó nhiều hơn một dòng với thử nghiệm thích hợp.
studgeek

12
@CecilCurry: Tôi chắc chắn bạn là một lập trình viên tuyệt vời, nhưng tôi không chắc có trường hợp nào bạn chưa từng xem là chỉ cần xem các câu trả lời khác ở đây để biết ví dụ. Đó là lý do tại sao tôi luôn chọn thư viện, vì đó là kinh nghiệm tổng hợp của nhiều nhà phát triển hơn là chỉ tôi.
Michael Scheper

104

Tôi không biết tại sao những điều này lại quá phức tạp.

trong hầu hết các trường hợp, biểu thức đơn giản ([A-Z]+)sẽ thực hiện thủ thuật

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

Để bỏ qua ký tự đầu tiên, chỉ cần thêm nhìn phía sau (?!^)

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

Nếu bạn muốn tách ALLCaps thành all_caps và mong đợi các số trong chuỗi của mình, bạn vẫn không cần thực hiện hai lần chạy riêng biệt, chỉ cần sử dụng |Biểu thức này ((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))có thể xử lý mọi tình huống trong sách

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

Tất cả phụ thuộc vào những gì bạn muốn vì vậy hãy sử dụng giải pháp phù hợp nhất với nhu cầu của bạn vì nó không quá phức tạp.

Xin chào!


1
Lặp lại cuối cùng là thông minh nhất, IMO. Tôi phải mất một chút để hiểu rằng nó chỉ thay thế một ký tự duy nhất ở đầu mỗi từ - và đó chỉ là do cách tiếp cận khác với cách tôi tự nghĩ ra. Làm rất tốt
Justin Miller

2
Tôi đã bối rối bởi (?!^)biểu hiện được gọi là nhìn phía sau. Trừ khi tôi thiếu một cái gì đó, những gì chúng ta thực sự muốn ở đây là một cái nhìn tiêu cực nên được thể hiện như là (?<!^). Vì những lý do tôi không thể hiểu được cái nhìn tiêu cực của bạn (?!^)dường như cũng có tác dụng ...
Apterx

7
Điều này không xử lý tốt các dấu gạch dưới có sẵn: "Camel2WARNING_Case_CASE"trở thành "camel2_warning_case__case". Bạn có thể thêm một cái nhìn (?<!_)tiêu cực, để giải quyết nó: re.sub('((?<=[a-z0-9])[A-Z]|(?!^)(?<!_)[A-Z](?=[a-z]))', r'_\1', "Camel2WARNING_Case_CASE").lower() trả về 'camel2_warning_case_case'
luckydonald

@Apteryx Bạn nói đúng, (?!^)được gọi không chính xác là "nhìn phía sau" và thay vào đó nên được gọi là một khẳng định nhìn tiêu cực . Như lời giải thích hay này cho thấy, những cái nhìn tiêu cực thường xuất hiện sau biểu thức bạn đang tìm kiếm. Vì vậy, bạn có thể nghĩ (?!^)là "tìm ''nơi <start of string>không theo". Thật vậy, một cái nhìn tiêu cực cũng hoạt động: bạn có thể nghĩ (?<!^)là "tìm ''nơi <start of string>không có trước".
Nathaniel Jones

17

chuỗi là thư viện đi đến của tôi cho điều này; ví dụ:

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

11

Cá nhân tôi không chắc chắn làm thế nào bất cứ điều gì sử dụng biểu thức thông thường trong python có thể được mô tả là thanh lịch. Hầu hết các câu trả lời ở đây chỉ là thực hiện thủ thuật RE kiểu "golf golf". Mã hóa thanh lịch được cho là dễ hiểu.

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
+=trên dây hầu như luôn luôn là một ý tưởng tồi. Nối vào một danh sách và ''.join()cuối cùng. Hoặc trong trường hợp này, chỉ cần tham gia với dấu gạch dưới ...
ThiefMaster

21
Làm thế nào là một biểu thức chính quy một dòng không hoàn toàn vượt trội về mọi cách thực tế (bao gồm cả khả năng đọc) đối với phép lặp ký tự đa dòng không hiệu quả và munging chuỗi brute-force? Python cung cấp hỗ trợ biểu thức chính quy ngoài luồng vì một lý do.
Cecil Curry

1
@CecilCurry - Biểu thức chính quy rất phức tạp. Xem trình biên dịch và trình phân tích cú pháp mà Python sử dụng: svn.python.org/projects/python/trunk/Lib/sre_compile.py & svn.python.org/projects/python/trunk/Lib/sre_parse.py - Thao tác chuỗi đơn giản như điều này có thể nhanh hơn nhiều so với một RE làm tương tự.
Evan Borgstrom

1
+1. Regexes có thể là một CPU chìm thực sự và trên các tính toán chuyên sâu sẽ làm giảm đáng kể hiệu suất của bạn. Đối với các nhiệm vụ đơn giản, luôn luôn thích các chức năng đơn giản.
Fabien

4
"Đối với các nhiệm vụ đơn giản, luôn thích các chức năng đơn giản" chắc chắn là lời khuyên tốt, nhưng câu trả lời này không phải là một chức năng đơn giản cũng không phải là một chức năng thanh lịch. Regex có thể chậm hơn, nhưng mặc định cho một chức năng phức tạp như thế này (đó là chưa được kiểm tra và có nhiều điểm lỗi tiềm ẩn) là tối ưu hóa hoàn toàn sớm
kevlarr

9

Tôi muốn tránh renếu có thể:

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
Đây là cái nhỏ gọn nhất tránh sử dụng rethư viện và thực hiện công cụ chỉ trong một dòng chỉ sử dụng str.methods tích hợp! Nó tương tự như câu trả lời này , nhưng tránh sử dụng cắt và bổ sung if ... elsebằng cách đơn giản là tước "_" như là ký tự đầu tiên. Tôi thích điều này nhất.
colidyre

Đối với câu trả lời được chấp nhận 6.81 µs ± 22.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)nhưng cho phản hồi 2.51 µs ± 25.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)này nhanh hơn 2,5 lần! Thích cái này!
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

Tôi nghĩ rằng giải pháp này đơn giản hơn các câu trả lời trước:

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

Đầu ra nào:

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

Biểu thức chính quy khớp với ba mẫu:

  1. [A-Z]?[a-z]+: Liên tiếp các chữ cái viết thường tùy ý bắt đầu bằng một chữ cái viết hoa.
  2. [A-Z]{2,}(?=[A-Z][a-z]|\d|\W|$): Hai hoặc nhiều chữ cái viết hoa liên tiếp. Nó sử dụng một cái nhìn để loại trừ chữ cái viết hoa cuối cùng nếu nó được theo sau bởi một chữ cái viết thường.
  3. \d+: Số liên tiếp.

Bằng cách sử dụng, re.findallchúng tôi nhận được một danh sách các "từ" riêng lẻ có thể được chuyển đổi thành chữ thường và được nối với dấu gạch dưới.


1
Có một ví dụ điển hình ở đây để lấy Mã số được mã hóa độc lập.
math_law

1
Bị hỏng: convert ("aB") -> 'a'
adw

5

Tôi không biết tại sao sử dụng cả hai cuộc gọi .sub ()? :) Tôi không phải là regex guru, nhưng tôi đã đơn giản hóa chức năng này, phù hợp với nhu cầu nhất định của tôi, tôi chỉ cần một giải pháp để chuyển đổi camelCasingVars từ yêu cầu POST sang vars_with_underscore:

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

Nó không hoạt động với những cái tên như getHTTPResponse, vì tôi nghe nói đó là quy ước đặt tên không tốt (nên giống như getHttpResponse, rõ ràng là việc ghi nhớ biểu mẫu này dễ dàng hơn nhiều).


Tôi quên đề cập rằng, '{1}' là không cần thiết, nhưng đôi khi nó giúp làm rõ một số sương mù.
tuyệt vọng4

2
-1: điều này không hoạt động. Ví dụ 'HTTPConnectionFactory', hãy thử với mã của bạn tạo ra 'h_tt_pconnection_factory', mã từ câu trả lời được chấp nhận tạo ra'http_connection_factory'
vartec

4

Đây là giải pháp của tôi:

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)

Nó hỗ trợ những trường hợp góc được thảo luận trong các ý kiến. Ví dụ, nó sẽ chuyển đổi getHTTPResponseCodethành get_http_response_codenhư nó nên.


7
-1 vì điều này rất phức tạp so với việc sử dụng regexps.
Eric O Lebigot

7
EOL, tôi chắc chắn nhiều người không phải là người tái chế sẽ nghĩ khác.
Evan Fosmark

Giải pháp này thất bại trong các trường hợp này: _Method, _test_Method , __test__Method, getHTTPrespnseCode, __get_HTTPresponseCode, _Camel_Case, _Test và _test_Method.
freegnu

3
@Evan, những người đó sẽ là những lập trình viên tồi.
Jesse Dhillon

3

Đối với niềm vui của nó:

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

Hoặc, nhiều hơn cho niềm vui của nó:

>>> 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 () chứ không phải c trong ABCEF ... Z
Jimmy

1
Python không có regexes? Nhanh chóng 's / [az] \ K ([AZ] [az]) / _ \ L $ 1 / g; lc $ _ 'trong Perl thực hiện công việc (mặc dù nó không xử lý tốt getHTTPResponseCode; nhưng điều đó được mong đợi, nên được đặt tên là getHttpResponseCode)
jrockway

5
str.joinđã được chấp thuận cho các lứa tuổi . Sử dụng ''.join(..)thay thế.
John Fouhy

jrockway: Nó có các biểu thức chính quy, thông qua mô-đun "re". Không quá khó để thực hiện công việc này bằng cách sử dụng regex thay vì các phương pháp được đăng ở đây.
Matthew Iselin

Python noob ở đây, nhưng tại sao lại trả về str.join ('', đầu ra)? Chỉ để tạo một bản sao?
Tarks

3

Sử dụng regexes có thể là ngắn nhất, nhưng giải pháp này dễ đọc hơn:

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 hoàn toàn không liên quan, câu hỏi này không liên quan gì đến django.
3k-

Đây chỉ là một ví dụ, như HTTPResponseCode, được xử lý bởi stackoverflow.com/a/23561109/15690 .
xanh

3

Vì vậy, nhiều phương pháp phức tạp ... Chỉ cần tìm tất cả nhóm "Có tiêu đề" và tham gia biến thể có vỏ dưới của nó với dấu gạch dưới.

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

Nếu bạn không muốn tạo số như ký tự đầu tiên của nhóm hoặc nhóm riêng - bạn có thể sử dụng ([A-z][a-z0-9]*)mặt nạ.



2

Đây không phải là một phương pháp tao nhã, là một triển khai rất 'cấp độ thấp' của một máy trạng thái đơn giản (máy trạng thái bitfield), có thể là chế độ chống pythonic nhất để giải quyết vấn đề này, tuy nhiên mô-đun lại cũng thực hiện một máy trạng thái quá phức tạp để giải quyết đơn giản này nhiệm vụ, vì vậy tôi nghĩ rằng đây là một giải pháp tốt.

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 có thể phân tích cú pháp tất cả các loại trường hợp: UpperSEQUENCEInterleaved, under_score, BIG_SYMBOLS và cammelCasingMethods

Tôi hy vọng nó hữu ích


1
Thật gớm ghiếc, nhưng nó chạy nhanh hơn khoảng 3 lần so với phương thức regex trên máy của tôi. :)
jdiaz5513


1

Hãy nhìn vào lib Schographics xuất sắc

https://github.com/schapes/schapes

Nó cho phép bạn tạo các cấu trúc dữ liệu đã nhập có thể tuần tự hóa / giải tuần tự hóa từ python sang hương vị Javascript, ví dụ:

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

Phương pháp đơn giản này nên thực hiện công việc:

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()
  • Chúng tôi tìm kiếm các chữ cái in hoa được đặt trước bởi bất kỳ số lượng chữ cái viết hoa (hoặc không) nào, và theo sau là bất kỳ số lượng ký tự viết thường.
  • Một dấu gạch dưới được đặt ngay trước khi xuất hiện chữ in hoa cuối cùng được tìm thấy trong nhóm và người ta có thể đặt trước chữ in hoa đó trong trường hợp nó được đặt trước các chữ in hoa khác.
  • Nếu có dấu gạch dưới, hãy loại bỏ chúng.
  • Cuối cùng, toàn bộ chuỗi kết quả được thay đổi thành chữ thường.

(lấy từ đây , xem ví dụ làm việc trực tuyến )


Đây là một câu trả lời cho câu hỏi ngược lại (làm thế nào để chuyển đổi sang trường hợp lạc đà).
Justin

1

Wow tôi đã đánh cắp điều này từ đoạn trích django. tham khảo http://djangosnippets.org/snippets/585/

Khá thanh lịch

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

Thí dụ:

camelcase_to_underscore('ThisUser')

Trả về:

'this_user'

ĐĂNG KÝ DEMO


1
Hình thức xấu sử dụng str làm tên biến cục bộ.
freegnu

Điều này thất bại thảm hại nếu có bất kỳ dấu gạch dưới nào ở đầu hoặc cuối chuỗi và nếu có bất kỳ dấu gạch dưới nào trước một chữ in hoa.
freegnu

không tính đến số tài khoản 😬
villy393

Đôi khi nó không phải là một ý tưởng tốt để đánh cắp mã.
colidyre

0

Một ví dụ khủng khiếp khi sử dụng các biểu thức thông thường (bạn có thể dễ dàng xóa phần này :)):

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

Hoạt động cho getHTTPResponseCode mặc dù!

Ngoài ra, sử dụng lambda:

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: Cũng khá dễ dàng để thấy rằng có chỗ để cải thiện cho các trường hợp như "Thử nghiệm", bởi vì dấu gạch dưới được chèn vô điều kiện.


0

Đây là điều tôi đã làm để thay đổi các tiêu đề trên một tệp được phân định bằng tab. Tôi đang bỏ qua phần mà tôi chỉ chỉnh sửa dòng đầu tiên của tệp. Bạn có thể điều chỉnh nó thành Python khá dễ dàng với thư viện re. Điều này cũng bao gồm tách các số (nhưng giữ các chữ số với nhau). Tôi đã làm điều đó trong hai bước bởi vì điều đó dễ hơn là bảo nó không đặt dấu gạch dưới ở đầu dòng hoặc tab.

Bước một ... tìm chữ cái in hoa hoặc số nguyên đứng trước chữ cái viết thường và đặt trước chúng bằng dấu gạch dưới:

Tìm kiếm:

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

Thay thế:

\1_\l\2/

Bước hai ... lấy phần trên và chạy lại để chuyển đổi tất cả chữ hoa sang chữ thường:

Tìm kiếm:

([A-Z])

Thay thế (đó là dấu gạch chéo ngược, chữ thường L, dấu gạch chéo ngược, một):

\l\1

0

Tôi đang tìm kiếm một giải pháp cho cùng một vấn đề, ngoại trừ việc tôi cần một chuỗi; ví dụ

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

Bắt đầu từ các giải pháp hai từ tốt đẹp ở đây, tôi đã đưa ra những điều sau đây:

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

Hầu hết các logic phức tạp là để tránh hạ từ đầu tiên. Đây là phiên bản đơn giản hơn nếu bạn không thay đổi từ đầu tiên:

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

Tất nhiên, bạn có thể biên dịch trước các biểu thức thông thường hoặc tham gia với dấu gạch dưới thay vì dấu gạch nối, như được thảo luận trong các giải pháp khác.


0

Súc tích mà không có biểu thức chính quy, nhưng HTTPResponseCode => omepresponse_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

Không có bất kỳ thư viện:

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

Hơi nặng, nhưng

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

0

RegEx rất hay được đề xuất trên trang này :

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

Nếu python có phương thức String Split, nó sẽ hoạt động ...

Trong Java:

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

Thật không may, mô-đun biểu thức chính quy Python không (kể từ phiên bản 3.6) hỗ trợ phân tách trên các kết quả khớp có độ dài bằng không.
tốc độ

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

Và nếu chúng ta cần bao gồm một trường hợp với đầu vào chưa được cameled:

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

0

Chỉ trong trường hợp ai đó cần chuyển đổi một tệp nguồn hoàn chỉnh, đây là một kịch bản sẽ làm điều đó.

# 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

Tôi đã có khá may mắn với điều này:

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)

Điều này rõ ràng có thể được tối ưu hóa cho tốc độ một nhỏ chút nếu bạn muốn.

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

Sử dụng: str.capitalize() để chuyển đổi chữ cái đầu tiên của chuỗi (chứa trong biến str) thành chữ in hoa và trả về toàn bộ chuỗi.

Ví dụ: Lệnh: "hello" .capitalize () Kết quả: Xin chào


Điều này không liên quan đến câu hỏi - OP muốn CamelCase -> Snake_case, không phải Viết hoa.
Brad Koch
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.