332 Stimmen

Elegante Python-Funktion zur Umwandlung von CamelCase in snake_case?

Exemple :

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

14voto

rspeed Punkte 1552

Ich denke, diese Lösung ist einfacher als die vorherigen Antworten:

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

Welche Ausgaben:

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

Der reguläre Ausdruck entspricht drei Mustern:

  1. [A-Z]?[a-z]+ : Aufeinanderfolgende Kleinbuchstaben, die optional mit einem Großbuchstaben beginnen.
  2. [A-Z]{2,}(?=[A-Z][a-z]|\d|\W|$) : Zwei oder mehr aufeinanderfolgende Großbuchstaben. Mit Hilfe einer Vorausschau wird der letzte Großbuchstabe ausgeschlossen, wenn er von einem Kleinbuchstaben gefolgt wird.
  3. \d+ : Fortlaufende Nummern.

Durch die Verwendung von re.findall erhalten wir eine Liste von einzelnen "Wörtern", die in Kleinbuchstaben umgewandelt und mit Unterstrichen verbunden werden können.

8voto

TehTris Punkte 3051

Ich persönlich bin mir nicht sicher, wie etwas, das reguläre Ausdrücke in Python verwendet, als elegant bezeichnet werden kann. Die meisten Antworten hier sind nur "Code-Golf" Typ RE Tricks. Elegante Kodierung sollte leicht verständlich sein.

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'

7voto

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

4voto

desper4do Punkte 1

Ich verstehe nicht, warum ich beide .sub()-Aufrufe verwende:) Ich bin kein Regex-Guru, aber ich vereinfachte Funktion zu dieser, die für meine bestimmten Bedürfnisse geeignet ist, ich brauchte nur eine Lösung, um camelCasedVars von POST-Anfrage zu vars_with_underscore zu konvertieren:

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

Es funktioniert nicht mit solchen Namen wie getHTTPResponse, weil ich gehört habe, dass es eine schlechte Namenskonvention ist (sollte wie getHttpResponse sein, es ist offensichtlich, dass es viel einfacher ist, sich diese Form zu merken).

4voto

Evan Fosmark Punkte 93825

Hier ist meine Lösung:

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)

Sie unterstützt die in den Kommentaren angesprochenen Eckfälle. Zum Beispiel wird es konvertieren getHTTPResponseCode a get_http_response_code wie es sein sollte.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X