Beispiel:
>>> convert('CamelCase')
'camel_case'
NotCamelCase
aberthisIs
Beispiel:
>>> convert('CamelCase')
'camel_case'
NotCamelCase
aberthisIs
Antworten:
import re
name = 'CamelCaseName'
name = re.sub(r'(?<!^)(?=[A-Z])', '_', name).lower()
print(name) # camel_case_name
Wenn Sie dies viele Male tun und das oben Gesagte langsam ist, kompilieren Sie den regulären Ausdruck im Voraus:
pattern = re.compile(r'(?<!^)(?=[A-Z])')
name = pattern.sub('_', name).lower()
Speziell für fortgeschrittenere Fälle (dies ist nicht mehr umkehrbar):
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
not_camel_case
in notCamelCase
und / oder NotCamelCase
?
s2.replace('__', '_')
Es gibt eine Flexionsbibliothek im Paketindex, die diese Dinge für Sie erledigen kann. In diesem Fall würden Sie suchen inflection.underscore()
:
>>> inflection.underscore('CamelCase')
'camel_case'
Ich weiß nicht, warum das alles so kompliziert ist.
für die meisten Fälle, die einfachen Ausdruck ([A-Z]+)
den Trick
>>> 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'
Um das erste Zeichen zu ignorieren, fügen Sie einfach einen Blick nach hinten hinzu (?!^)
>>> 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'
Wenn Sie ALLCaps von all_caps trennen möchten und Zahlen in Ihrer Zeichenfolge erwarten möchten, müssen Sie immer noch nicht zwei separate Läufe ausführen. Verwenden Sie einfach. |
Dieser Ausdruck ((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))
kann nahezu jedes Szenario im Buch verarbeiten
>>> 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'
Es hängt alles davon ab, was Sie möchten. Verwenden Sie daher die Lösung, die Ihren Anforderungen am besten entspricht, da sie nicht zu kompliziert sein sollte.
nJoy!
(?!^)
Ausdruck, der als Rückblick bezeichnet wurde. Wenn ich nichts vermisse, wollen wir hier wirklich einen negativen Rückblick, der ausgedrückt werden sollte als (?<!^)
. Aus Gründen, die ich nicht verstehen kann, (?!^)
scheint Ihr negativer Ausblick auch zu funktionieren ...
"Camel2WARNING_Case_CASE"
wird "camel2_warning_case__case"
. Sie können ein (?<!_)
negatives Aussehen hinzufügen , um es zu lösen: re.sub('((?<=[a-z0-9])[A-Z]|(?!^)(?<!_)[A-Z](?=[a-z]))', r'_\1', "Camel2WARNING_Case_CASE").lower()
Rückkehr 'camel2_warning_case_case'
(?!^)
wurde fälschlicherweise als "Blick nach hinten" bezeichnet und hätte stattdessen als negative Lookahead-Behauptung bezeichnet werden sollen . Wie diese nette Erklärung zeigt, kommen negative Lookaheads normalerweise nach dem Ausdruck , nach dem Sie suchen. Sie können sich also (?!^)
als "Finden, ''
wo <start of string>
nicht folgt" vorstellen. In der Tat funktioniert auch ein negativer Lookbehind: Sie können sich vorstellen, (?<!^)
"herauszufinden, ''
wo <start of string>
nicht vorangeht".
stringcase ist dafür meine Anlaufstelle ; z.B:
>>> from stringcase import pascalcase, snakecase
>>> snakecase('FooBarBaz')
'foo_bar_baz'
>>> pascalcase('foo_bar_baz')
'FooBarBaz'
Persönlich bin ich mir nicht sicher, wie etwas, das reguläre Ausdrücke in Python verwendet, als elegant beschrieben werden kann. Die meisten Antworten hier machen nur RE-Tricks vom Typ "Code Golf". Elegante Codierung soll 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'
+=
auf Saiten ist fast immer eine schlechte Idee. An eine Liste anhängen und ''.join()
am Ende. Oder in diesem Fall einfach mit einem Unterstrich verbinden ...
Ich vermeide es re
wenn möglich:
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'
re
Bibliothek zu verwenden und das Zeug nur in einer Zeile zu erledigen, nur mit eingebauten str.methods! Es ähnelt dieser Antwort , vermeidet jedoch das Verwenden von Slicing und zusätzlichem, if ... else
indem möglicherweise das potenziell hinzugefügte "_" als erstes Zeichen entfernt wird. Das gefällt mir am besten.
6.81 µs ± 22.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
aber für diese Antwort, 2.51 µs ± 25.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
die 2,5x schneller ist! Ich liebe das!
Ich denke, diese Lösung ist einfacher als frühere 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 Ausgänge:
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:
[A-Z]?[a-z]+
: Aufeinanderfolgende Kleinbuchstaben, die optional mit einem Großbuchstaben beginnen.[A-Z]{2,}(?=[A-Z][a-z]|\d|\W|$)
: Zwei oder mehr aufeinanderfolgende Großbuchstaben. Es verwendet einen Lookahead, um den letzten Großbuchstaben auszuschließen, wenn ihm ein Kleinbuchstabe folgt.\d+
: Fortlaufende Nummern.Durch die Verwendung erhalten re.findall
wir eine Liste einzelner "Wörter", die in Kleinbuchstaben umgewandelt und mit Unterstrichen verbunden werden können.
Ich habe keine Ahnung, warum beide .sub () -Aufrufe verwendet werden. :) Ich bin kein Regex-Guru, aber ich habe die Funktion auf diese vereinfacht, die für meine bestimmten Bedürfnisse geeignet ist. Ich brauchte nur eine Lösung, um camelCasedVars von der POST-Anfrage in vars_with_underscore zu konvertieren:
def myFunc(...):
return re.sub('(.)([A-Z]{1})', r'\1_\2', "iTriedToWriteNicely").lower()
Es funktioniert nicht mit Namen wie getHTTPResponse, weil ich gehört habe, dass es sich um eine schlechte Namenskonvention handelt (sollte wie getHttpResponse sein, es ist offensichtlich, dass es viel einfacher ist, sich dieses Formular zu merken).
'HTTPConnectionFactory'
, Ihr Code erzeugt 'h_tt_pconnection_factory'
, Code aus akzeptierter Antwort erzeugt'http_connection_factory'
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)
Es unterstützt die in den Kommentaren diskutierten Eckfälle. Zum Beispiel wird es so konvertiert getHTTPResponseCode
, get_http_response_code
wie es sollte.
Spaßeshalber:
>>> 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'
Oder mehr zum Spaß:
>>> 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'
str.join
ist seit Ewigkeiten veraltet . Verwenden Sie ''.join(..)
stattdessen.
Die Verwendung von regulären Ausdrücken mag am kürzesten sein, aber diese Lösung ist viel besser lesbar:
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
So viele komplizierte Methoden ... Finden Sie einfach alle "Betitelten" Gruppen und verbinden Sie die Variante mit dem unteren Gehäuse mit Unterstrich.
>>> 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'
Wenn Sie keine Zahlen wie das erste Zeichen einer Gruppe oder eine separate Gruppe erstellen möchten, können Sie die ([A-z][a-z0-9]*)
Maske verwenden.
Nicht in der Standardbibliothek, aber ich habe dieses Skript gefunden , das anscheinend die Funktionen enthält, die Sie benötigen.
Dies ist keine elegante Methode, sondern eine Implementierung einer einfachen Zustandsmaschine (Bitfeld-Zustandsmaschine) auf sehr niedriger Ebene, möglicherweise der anti-pythonischste Modus, um dies zu beheben. Das Modul re implementiert jedoch auch eine zu komplexe Zustandsmaschine, um diese einfache zu lösen Aufgabe, also denke ich, dass dies eine gute Lösung ist.
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 kann alle Falltypen analysieren: UpperSEQUENCEInterleaved, under_score, BIG_SYMBOLS und cammelCasedMethods
Ich hoffe es ist nützlich
Leicht angepasst von https://stackoverflow.com/users/267781/matth , die Generatoren verwenden.
def uncamelize(s):
buff, l = '', []
for ltr in s:
if ltr.isupper():
if buff:
l.append(buff)
buff = ''
buff += ltr
l.append(buff)
return '_'.join(l).lower()
Schauen Sie sich die exzellente Schematics lib an
https://github.com/schematics/schematics
Sie können typisierte Datenstrukturen erstellen, die von Python nach Javascript serialisiert / deserialisiert werden können, z.
class MapPrice(Model):
price_before_vat = DecimalType(serialized_name='priceBeforeVat')
vat_rate = DecimalType(serialized_name='vatRate')
vat = DecimalType()
total_price = DecimalType(serialized_name='totalPrice')
Diese einfache Methode sollte den Job erledigen:
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()
(von hier aus siehe Online-Arbeitsbeispiel )
Wow, ich habe das gerade aus Django-Schnipsel gestohlen. ref http://djangosnippets.org/snippets/585/
Ziemlich elegant
camelcase_to_underscore = lambda str: re.sub(r'(?<=[a-z])[A-Z]|[A-Z](?=[^A-Z])', r'_\g<0>', str).lower().strip('_')
Beispiel:
camelcase_to_underscore('ThisUser')
Kehrt zurück:
'this_user'
Ein schreckliches Beispiel mit regulären Ausdrücken (Sie könnten leicht bereinigen :)):
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")
Funktioniert aber für getHTTPResponseCode!
Alternativ mit 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")
BEARBEITEN: Es sollte auch ziemlich leicht zu erkennen sein, dass in Fällen wie "Test" Verbesserungspotenzial besteht, da der Unterstrich unbedingt eingefügt wird.
Hier ist etwas, was ich getan habe, um die Header einer durch Tabulatoren getrennten Datei zu ändern. Ich lasse den Teil weg, in dem ich nur die erste Zeile der Datei bearbeitet habe. Sie können es mit der Re-Bibliothek ziemlich einfach an Python anpassen. Dies beinhaltet auch das Trennen von Zahlen (hält aber die Ziffern zusammen). Ich habe es in zwei Schritten gemacht, weil das einfacher war, als zu sagen, dass am Anfang einer Zeile oder eines Tabulators kein Unterstrich gesetzt werden soll.
Erster Schritt ... Suchen Sie Großbuchstaben oder Ganzzahlen, denen Kleinbuchstaben vorangestellt sind, und stellen Sie ihnen einen Unterstrich voran:
Suche:
([a-z]+)([A-Z]|[0-9]+)
Ersatz:
\1_\l\2/
Schritt 2 ... Nehmen Sie die obigen Schritte und führen Sie sie erneut aus, um alle Großbuchstaben in Kleinbuchstaben umzuwandeln:
Suche:
([A-Z])
Ersatz (das ist Backslash, Kleinbuchstabe L, Backslash, eins):
\l\1
Ich suchte nach einer Lösung für das gleiche Problem, außer dass ich eine Kette brauchte; z.B
"CamelCamelCamelCase" -> "Camel-camel-camel-case"
Ausgehend von den netten Zwei-Wort-Lösungen hier habe ich Folgendes gefunden:
"-".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"))
Der größte Teil der komplizierten Logik besteht darin, zu vermeiden, dass das erste Wort in Kleinbuchstaben geschrieben wird. Hier ist eine einfachere Version, wenn es Ihnen nichts ausmacht, das erste Wort zu ändern:
"-".join(x.group(1).lower() for x in re.finditer("(^[^A-Z]+|[A-Z][^A-Z]+)", "stringToSplit"))
Natürlich können Sie die regulären Ausdrücke vorkompilieren oder mit einem Unterstrich anstelle eines Bindestrichs verbinden, wie in den anderen Lösungen beschrieben.
Prägnant ohne reguläre Ausdrücke, aber 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())])
Ohne Bibliothek:
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('__','_')
Ein bisschen schwer, aber
CamelCamelCamelCase -> camel_camel_camel_case
HTTPRequest -> http_request
GetHTTPRequest -> get_http_request
getHTTPRequest -> get_http_request
Sehr schönes RegEx auf dieser Seite vorgeschlagen :
(?<!^)(?=[A-Z])
Wenn Python eine String Split-Methode hat, sollte es funktionieren ...
In Java:
String s = "loremIpsum";
words = s.split("(?<!^)(?=[A-Z])");
def convert(name):
return reduce(
lambda x, y: x + ('_' if y.isupper() else '') + y,
name
).lower()
Und wenn wir einen Fall mit bereits nicht getarntem Input abdecken müssen:
def convert(name):
return reduce(
lambda x, y: x + ('_' if y.isupper() and not x.endswith('_') else '') + y,
name
).lower()
Nur für den Fall, dass jemand eine vollständige Quelldatei transformieren muss, finden Sie hier ein Skript, das dies ausführt.
# 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))
Ich hatte ziemlich viel Glück mit diesem:
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)
Dies könnte natürlich für die Geschwindigkeit eines optimiert werden winzige Bit , wenn Sie wollen.
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)
Verwenden Sie:, str.capitalize()
um den ersten Buchstaben der Zeichenfolge (in der Variablen str enthalten) in einen Großbuchstaben umzuwandeln und die gesamte Zeichenfolge zurückzugeben.
Beispiel: Befehl: "Hallo" .capitalize () Ausgabe: Hallo