¿Elegante función de Python para convertir CamelCase a Snake_case?

Resuelto Sridhar Ratnakumar asked hace 15 años • 29 respuestas

Ejemplo:

>>> convert('CamelCase')
'camel_case'
Sridhar Ratnakumar avatar Jul 24 '09 07:07 Sridhar Ratnakumar
Aceptado

Caso de camello a caso de serpiente

import re

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

Si haces esto muchas veces y lo anterior es lento, compila la expresión regular de antemano:

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

Para manejar casos más avanzados especialmente (esto ya no es reversible):

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

Para agregar también casos con dos guiones bajos o más:

def to_snake_case(name):
    name = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
    name = re.sub('__([A-Z])', r'_\1', name)
    name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', name)
    return name.lower()

Caso serpiente a caso pascal

name = 'snake_case_name'
name = ''.join(word.title() for word in name.split('_'))
print(name)  # SnakeCaseName
epost avatar Jul 24 '2009 06:07 epost

Hay una biblioteca de inflexión en el índice del paquete que puede manejar estas cosas por usted. En este caso, estaría buscando inflection.underscore():

>>> inflection.underscore('CamelCase')
'camel_case'
 avatar Jun 26 '2013 19:06

No sé por qué todo esto es tan complicado.

en la mayoría de los casos, la expresión simple ([A-Z]+)funcionará

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

Para ignorar el primer carácter simplemente agregue mirar atrás(?!^)

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

Si desea separar ALLCaps de all_caps y esperar números en su cadena, aún no necesita hacer dos ejecuciones separadas, solo use |esta expresión que ((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))puede manejar casi todos los escenarios del libro.

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

Todo depende de lo que quieras así que utiliza la solución que mejor se adapte a tus necesidades ya que no debería ser demasiado complicada.

¡Alegría!

nickl- avatar Oct 12 '2012 21:10 nickl-