Thí dụ:
>>> convert('CamelCase')
'camel_case'
NotCamelCase
nhưngthisIs
Thí dụ:
>>> convert('CamelCase')
'camel_case'
NotCamelCase
nhưngthisIs
Câu trả lời:
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
name = 'snake_case_name'
name = ''.join(word.title() for word in name.split('_'))
print(name) # SnakeCaseName
not_camel_case
để notCamelCase
và / hoặc NotCamelCase
?
s2.replace('__', '_')
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'
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!
(?!^)
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 ...
"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'
(?!^)
đượ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".
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'
+=
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 ...
Tôi muốn tránh re
nế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'
re
thư 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 ... else
bằ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.
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!
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:
[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.[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.\d+
: Số liên tiếp.Bằng cách sử dụng, re.findall
chú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.
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).
'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'
Đâ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 getHTTPResponseCode
thành get_http_response_code
như nó nên.
Đố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'
str.join
đã được chấp thuận cho các lứa tuổi . Sử dụng ''.join(..)
thay thế.
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
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ạ.
Không có trong thư viện tiêu chuẩn, nhưng tôi thấy tập lệnh này có vẻ chứa chức năng bạn cần.
Đâ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
Thích nghi nhẹ từ https://stackoverflow.com/users/267781/matth người sử dụng máy phát điện.
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()
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')
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()
(lấy từ đây , xem ví dụ làm việc trực tuyến )
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'
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.
Đâ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
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.
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())])
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
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("(?<!^)(?=[A-Z])");
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()
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))
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)
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