Contoh:
>>> convert('CamelCase')
'camel_case'
NotCamelCase
tapithisIs
Contoh:
>>> convert('CamelCase')
'camel_case'
NotCamelCase
tapithisIs
Jawaban:
import re
name = 'CamelCaseName'
name = re.sub(r'(?<!^)(?=[A-Z])', '_', name).lower()
print(name) # camel_case_name
Jika Anda melakukan ini berulang kali dan yang di atas lambat, kompilasi regex sebelumnya:
pattern = re.compile(r'(?<!^)(?=[A-Z])')
name = pattern.sub('_', name).lower()
Untuk menangani kasus yang lebih canggih secara khusus (ini tidak dapat dibalik lagi):
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
ke notCamelCase
dan / atau NotCamelCase
?
s2.replace('__', '_')
Ada perpustakaan infleksi dalam indeks paket yang dapat menangani hal-hal ini untuk Anda. Dalam hal ini, Anda akan mencari inflection.underscore()
:
>>> inflection.underscore('CamelCase')
'camel_case'
Saya tidak tahu mengapa ini semua sangat menyulitkan.
untuk sebagian besar kasus, ekspresi sederhana ([A-Z]+)
akan berhasil
>>> 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'
Untuk mengabaikan karakter pertama cukup tambahkan tampilan di belakang (?!^)
>>> 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'
Jika Anda ingin memisahkan ALLCaps ke all_caps dan mengharapkan angka dalam string Anda, Anda masih tidak perlu melakukan dua run terpisah gunakan saja. |
Ungkapan ini ((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))
dapat menangani hampir setiap skenario di buku
>>> 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'
Itu semua tergantung pada apa yang Anda inginkan jadi gunakan solusi yang paling sesuai dengan kebutuhan Anda karena tidak boleh terlalu rumit.
nJoy!
(?!^)
ekspresi yang disebut melihat-belakang. Kecuali jika saya melewatkan sesuatu, yang benar-benar kita inginkan di sini adalah pandangan negatif yang harus diungkapkan (?<!^)
. Untuk alasan yang saya tidak bisa mengerti pandangan negatif Anda (?!^)
tampaknya bekerja juga ...
"Camel2WARNING_Case_CASE"
menjadi "camel2_warning_case__case"
. Anda dapat menambahkan tampilan (?<!_)
negatif di belakang, untuk menyelesaikannya: re.sub('((?<=[a-z0-9])[A-Z]|(?!^)(?<!_)[A-Z](?=[a-z]))', r'_\1', "Camel2WARNING_Case_CASE").lower()
pengembalian 'camel2_warning_case_case'
(?!^)
secara keliru disebut "lihat di belakang" dan seharusnya disebut pernyataan pencarian yang negatif . Seperti yang ditunjukkan penjelasan yang bagus ini , lookaheads negatif biasanya muncul setelah ekspresi yang Anda cari. Jadi Anda dapat menganggapnya (?!^)
sebagai "menemukan di ''
mana <start of string>
tidak mengikuti". Memang, tampilan negatif di belakang juga berfungsi: Anda dapat menganggapnya (?<!^)
sebagai "menemukan di ''
mana <start of string>
tidak mendahului".
stringcase adalah perpustakaan pilihan saya untuk ini; misalnya:
>>> from stringcase import pascalcase, snakecase
>>> snakecase('FooBarBaz')
'foo_bar_baz'
>>> pascalcase('foo_bar_baz')
'FooBarBaz'
Saya lebih suka menghindari re
jika mungkin:
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
perpustakaan dan melakukan hal-hal hanya dalam satu baris hanya menggunakan str.methods built-in! Ini mirip dengan jawaban ini , tetapi hindari menggunakan pengirisan dan tambahan if ... else
dengan hanya mengupas yang berpotensi ditambahkan "_" sebagai karakter pertama. Saya sangat suka ini.
6.81 µs ± 22.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
tetapi untuk respons ini 2.51 µs ± 25.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
yang 2,5 kali lebih cepat! Suka ini!
Secara pribadi saya tidak yakin bagaimana pun menggunakan ekspresi reguler dalam python dapat digambarkan sebagai elegan. Sebagian besar jawaban di sini hanya melakukan trik "kode golf" jenis RE. Pengkodean yang elegan seharusnya mudah dipahami.
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'
+=
pada string hampir selalu merupakan ide yang buruk. Tambahkan ke daftar dan ''.join()
pada akhirnya. Atau dalam hal ini, cukup bergabung dengan garis bawah ...
Saya pikir solusi ini lebih mudah daripada jawaban sebelumnya:
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))
Output yang mana:
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
Ekspresi reguler cocok dengan tiga pola:
[A-Z]?[a-z]+
: Huruf kecil berurutan yang secara opsional dimulai dengan huruf besar.[A-Z]{2,}(?=[A-Z][a-z]|\d|\W|$)
: Dua atau lebih huruf besar berturut-turut. Ini menggunakan lookahead untuk mengecualikan huruf besar terakhir jika diikuti oleh huruf kecil.\d+
: Nomor yang berurutan.Dengan menggunakan re.findall
kita mendapatkan daftar "kata-kata" individual yang dapat dikonversi menjadi huruf kecil dan digabungkan dengan garis bawah.
Saya tidak mengerti mengapa menggunakan keduanya .sub () panggilan? :) Saya bukan guru regex, tapi saya menyederhanakan fungsi yang satu ini, yang cocok untuk kebutuhan tertentu saya, saya hanya perlu solusi untuk mengkonversi camelCasedVars dari permintaan POST ke vars_with_underscore:
def myFunc(...):
return re.sub('(.)([A-Z]{1})', r'\1_\2', "iTriedToWriteNicely").lower()
Itu tidak bekerja dengan nama-nama seperti getHTTPResponse, karena saya dengar itu penamaan yang buruk (harus seperti getHttpResponse, itu jelas, bahwa lebih mudah menghafal formulir ini).
'HTTPConnectionFactory'
, kode Anda menghasilkan 'h_tt_pconnection_factory'
, kode dari jawaban yang diterima menghasilkan'http_connection_factory'
Inilah solusi saya:
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)
Ini mendukung kasus sudut yang dibahas dalam komentar. Misalnya, itu akan dikonversi getHTTPResponseCode
menjadi get_http_response_code
seperti seharusnya.
Untuk bersenang-senang:
>>> 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'
Atau, lebih untuk bersenang-senang:
>>> 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
telah usang sejak lama . Gunakan ''.join(..)
sebagai gantinya.
Menggunakan regex mungkin yang terpendek, tetapi solusi ini jauh lebih mudah dibaca:
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
Begitu banyak metode yang rumit ... Cukup temukan semua grup "Berjudul" dan gabungkan varian kase bawahnya dengan garis bawah.
>>> 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'
Jika Anda tidak ingin membuat angka seperti karakter pertama grup atau grup terpisah - Anda dapat menggunakan ([A-z][a-z0-9]*)
mask.
Tidak di perpustakaan standar, tetapi saya menemukan skrip ini yang tampaknya berisi fungsionalitas yang Anda butuhkan.
Ini bukan metode yang elegan, implementasi yang sangat 'rendah' dari mesin keadaan sederhana (mesin bitfield state), mungkin mode yang paling anti pythonic untuk menyelesaikan ini, namun modul ini juga menerapkan mesin keadaan terlalu rumit untuk menyelesaikan mesin sederhana ini. tugas, jadi saya pikir ini adalah solusi yang bagus.
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 dapat mem-parsing semua jenis kasus: UpperSEQUENCEDisatukan, under_score, BIG_SYMBOLS, dan cammelCasedMethods
Semoga bermanfaat
Diadaptasi secara ringan dari https://stackoverflow.com/users/267781/matth yang menggunakan generator.
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()
Lihatlah Schibatics lib yang luar biasa
https://github.com/schematics/schematics
Hal ini memungkinkan Anda untuk membuat struktur data yang diketik yang dapat membuat cerita bersambung / deserialize dari python ke Javascript, misalnya:
class MapPrice(Model):
price_before_vat = DecimalType(serialized_name='priceBeforeVat')
vat_rate = DecimalType(serialized_name='vatRate')
vat = DecimalType()
total_price = DecimalType(serialized_name='totalPrice')
Metode sederhana ini harus melakukan pekerjaan:
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()
(diambil dari sini , lihat contoh kerja online )
Wow saya baru saja mencuri ini dari potongan Django. ref http://djangosnippets.org/snippets/585/
Cukup elegan
camelcase_to_underscore = lambda str: re.sub(r'(?<=[a-z])[A-Z]|[A-Z](?=[^A-Z])', r'_\g<0>', str).lower().strip('_')
Contoh:
camelcase_to_underscore('ThisUser')
Pengembalian:
'this_user'
Contoh menghebohkan menggunakan ekspresi reguler (Anda dapat dengan mudah membersihkan ini :)):
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")
Bekerja untuk getHTTPResponseCode!
Atau, gunakan 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: Seharusnya juga cukup mudah untuk melihat bahwa ada ruang untuk perbaikan untuk kasus-kasus seperti "Tes", karena garis bawah dimasukkan tanpa syarat.
Berikut adalah sesuatu yang saya lakukan untuk mengubah header pada file yang dibatasi-tab. Saya menghilangkan bagian di mana saya hanya mengedit baris pertama file. Anda dapat mengadaptasinya ke Python dengan cukup mudah dengan pustaka ulang. Ini juga termasuk memisahkan angka-angka (tetapi menjaga angka bersama-sama). Saya melakukannya dalam dua langkah karena itu lebih mudah daripada mengatakannya untuk tidak meletakkan garis bawah pada awal baris atau tab.
Langkah Satu ... cari huruf besar atau bilangan bulat didahului dengan huruf kecil, dan awali dengan garis bawah:
Cari:
([a-z]+)([A-Z]|[0-9]+)
Penggantian:
\1_\l\2/
Langkah Dua ... ambil yang di atas dan jalankan lagi untuk mengonversi semua huruf besar menjadi huruf kecil:
Cari:
([A-Z])
Penggantian (yaitu backslash, huruf kecil L, backslash, satu):
\l\1
Saya mencari solusi untuk masalah yang sama, kecuali bahwa saya membutuhkan rantai; misalnya
"CamelCamelCamelCase" -> "Camel-camel-camel-case"
Mulai dari solusi dua kata yang bagus di sini, saya datang dengan yang berikut:
"-".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"))
Sebagian besar logika yang rumit adalah untuk menghindari mengurangi kata pertama. Ini versi yang lebih sederhana jika Anda tidak keberatan mengubah kata pertama:
"-".join(x.group(1).lower() for x in re.finditer("(^[^A-Z]+|[A-Z][^A-Z]+)", "stringToSplit"))
Tentu saja, Anda dapat melakukan pre-kompilasi ekspresi reguler atau bergabung dengan garis bawah alih-alih tanda hubung, seperti yang dibahas dalam solusi lain.
Ringkas tanpa ekspresi reguler, tetapi 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())])
Tanpa perpustakaan apa pun:
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('__','_')
Agak berat, tapi
CamelCamelCamelCase -> camel_camel_camel_case
HTTPRequest -> http_request
GetHTTPRequest -> get_http_request
getHTTPRequest -> get_http_request
RegEx yang sangat bagus diusulkan di situs ini :
(?<!^)(?=[A-Z])
Jika python memiliki metode String Split, itu harus berfungsi ...
Di Jawa:
String s = "loremIpsum";
words = s.split("(?<!^)(?=[A-Z])");
def convert(name):
return reduce(
lambda x, y: x + ('_' if y.isupper() else '') + y,
name
).lower()
Dan jika kita perlu membahas kasus dengan input yang sudah di-un-camel:
def convert(name):
return reduce(
lambda x, y: x + ('_' if y.isupper() and not x.endswith('_') else '') + y,
name
).lower()
Untuk berjaga-jaga jika seseorang perlu mengubah file sumber yang lengkap, berikut adalah skrip yang akan melakukannya.
# 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))
Saya cukup beruntung dengan yang ini:
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)
Ini jelas bisa dioptimalkan untuk kecepatan kecil sedikit jika Anda ingin.
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)
Menggunakan: str.capitalize()
untuk mengkonversi huruf pertama dari string (terkandung dalam variabel str) ke huruf kapital dan mengembalikan seluruh string.
Contoh: Perintah: "halo" .capitalize () Output: Halo