Другой способ взглянуть на это: Используются 64 бита для представления чисел. Как следствие, не может быть представлено более 2 ** 64 = 18 446 744 073 709 551 616 различных чисел.
Тем не менее, Math говорит, что существует уже бесконечное число десятичных знаков между 0 и 1. IEE 754 определяет кодировку для эффективного использования этих 64 бит для гораздо большего количества пробелов плюс NaN и +/- Infinity, поэтому есть пробелы между точно представленными числами, заполненными числами, только приближены.
К сожалению, 0,3 сидит в промежутке.
Это довольно подробно:
def convert(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()
Работает со всеми этими функциями (и не вредит уже не-верблюжьим версиям):
>>> convert('CamelCase')
'camel_case'
>>> convert('CamelCamelCase')
'camel_camel_case'
>>> convert('Camel2Camel2Case')
'camel2_camel2_case'
>>> convert('getHTTPResponseCode')
'get_http_response_code'
>>> convert('get2HTTPResponseCode')
'get2_http_response_code'
>>> convert('HTTPResponseCode')
'http_response_code'
>>> convert('HTTPResponseCodeXYZ')
'http_response_code_xyz'
вы будете называть это миллион раз, вы можете предварительно скомпилировать регулярные выражения:
first_cap_re = re.compile('(.)([A-Z][a-z]+)')
all_cap_re = re.compile('([a-z0-9])([A-Z])')
def convert(name):
s1 = first_cap_re.sub(r'\1_\2', name)
return all_cap_re.sub(r'\1_\2', s1).lower()
Не забудьте импортировать модуль регулярных выражений
import re
Кратко без регулярных выражений, но 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())])
Это не элегантный метод, это очень «низкий уровень» реализации простой конечной машины (конечный автомат битполя), возможно, самый антипитонический режим для решения этой проблемы, однако модуль также реализует слишком сложный конечный автомат для разрешите эту простую задачу, поэтому я думаю, что это хорошее решение.
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 может анализировать все типы case: UpperSEQUENCEInterleaved, under_score, BIG_SYMBOLS и cammelCasedMethods
Надеюсь, это полезно
Лично я не уверен, что все, что использует регулярные выражения в python, можно назвать элегантным. Большинство ответов здесь просто делают трюки типа «код гольфа» типа. Предполагается, что легкое кодирование должно быть понятным.
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'
Очень хороший RegEx, предложенный на на этом сайте :
(?<!^)(?=[A-Z])
Если python имеет метод String Split, он должен работать ...
In Java:
String s = "loremIpsum";
words = s.split("(?<!^)(?=[A-Z])");
Использование регулярных выражений может быть самым коротким, но это решение более читаемо:
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
Этот простой метод должен выполнить задание:
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()
(взято из здесь , см. рабочий пример онлайн )
Использовать: str.capitalize()
для преобразования первой буквы строки (содержащейся в переменной str) в заглавную букву и возвращает всю строку.
Пример: Команда: «hello» .capitalize () Выход : Hello
stringcase - это моя библиотека для этого; например ::
>>> from stringcase import pascalcase, snakecase
>>> snakecase('FooBarBaz')
'foo_bar_baz'
>>> pascalcase('foo_bar_baz')
'FooBarBaz'
Без какой-либо библиотеки:
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('__','_')
Немного тяжело, но
CamelCamelCamelCase -> camel_camel_camel_case
HTTPRequest -> http_request
GetHTTPRequest -> get_http_request
getHTTPRequest -> get_http_request
В индексе пакета есть библиотека флекса , которая может обрабатывать эти вещи для вас. В этом случае вы будете искать inflection.underscore()
:
>>> inflection.underscore('CamelCase')
'camel_case'
Ничего себе, я просто украл это из фрагментов django. ref http://djangosnippets.org/snippets/585/
Довольно элегантный
camelcase_to_underscore = lambda str: re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))', '_\\1', str).lower().strip('_')
Пример:
camelcase_to_underscore('ThisUser')
Возвраты:
'this_user'
Мне очень повезло с этим:
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)
Это может быть оптимизировано для скорости крошечного бит, если вы хотите.
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)
Я не понимаю, зачем использовать оба вызова .sub ()? :) Я не регулярный гуру, но я упростил эту функцию, которая подходит для моих определенных потребностей, мне просто нужно было решение для преобразования camelCasedVars из запроса POST в vars_with_underscore:
def myFunc(...):
return re.sub('(.)([A-Z]{1})', r'\1_\2', "iTriedToWriteNicely").lower()
It не работает с такими именами, как getHTTPResponse, потому что я слышал, что это плохое соглашение об именах (должно быть похоже на getHttpResponse, очевидно, что гораздо легче запомнить эту форму).
def convert(name):
return reduce(
lambda x, y: x + ('_' if y.isupper() else '') + y,
name
).lower()
И если нам нужно покрыть случай с уже неадаптивным вводом:
def convert(name):
return reduce(
lambda x, y: x + ('_' if y.isupper() and not x.endswith('_') else '') + y,
name
).lower()
Взгляните на превосходный Schematics lib
https://github.com/schematics/schematics
Он позволяет создавать типизированные данные структуры, которые могут сериализоваться / десериализоваться от питона до аромата Javascript, например:
class MapPrice(Model):
price_before_vat = DecimalType(serialized_name='priceBeforeVat')
vat_rate = DecimalType(serialized_name='vatRate')
vat = DecimalType()
total_price = DecimalType(serialized_name='totalPrice')
Я искал решение той же проблемы, за исключением того, что мне нужна цепочка; например,
"CamelCamelCamelCase" -> "Camel-camel-camel-case"
. Исходя из хороших двухсловных решений здесь, я придумал следующее:
"-".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"))
. Большая часть сложной логики заключается в том, чтобы избегать нижнего индекса первого слова , Вот более простая версия, если вы не возражаете изменить первое слово:
"-".join(x.group(1).lower() for x in re.finditer("(^[^A-Z]+|[A-Z][^A-Z]+)", "stringToSplit"))
Конечно, вы можете предварительно скомпилировать регулярные выражения или присоединиться к подчеркиванию вместо дефиса, как описано в других решениях .
''.join('_'+c.lower() if c.isupper() else c for c in "DeathToCamelCase").strip('_')
re.sub("(.)([A-Z])", r'\1_\2', 'DeathToCamelCase').lower()
Вот что я сделал, чтобы изменить заголовки в файле с разделителями табуляции. Я опускаю часть, где я только редактировал первую строку файла. Вы можете легко адаптировать его к Python с помощью библиотеки re. Это также включает разделение номеров (но сохраняет цифры вместе). Я сделал это за два шага, потому что это было проще, чем сказать, чтобы не подчеркивать в начале строки или вкладки.
Шаг первый ... найти заглавные буквы или целые числа, которым предшествуют строчные буквы, и перед ним обозначается символ подчеркивания:
Поиск:
([a-z]+)([A-Z]|[0-9]+)
Замена:
\1_\l\2/
Шаг второй ... возьмите вышеуказанное и снова запустите его конвертировать все кепки в нижний регистр:
Поиск:
([A-Z])
Замена (это обратная косая черта, нижний регистр L, обратная косая черта, одна):
\l\1
def convert(camel_str):
temp_list = []
for letter in camel_str:
if letter.islower():
temp_list.append(letter)
else:
temp_list.append('_')
temp_list.append(letter)
result = "".join(temp_list)
return result.lower()
Я не знаю, почему все это так усложняет.
для большинства случаев простое выражение ([A-Z]+)
выполнит трюк
>>> 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'
Чтобы игнорировать первый символ просто добавьте look behind (?!^)
>>> 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'
Если вы хотите отделить ALLCaps до all_caps и ожидать числа в вашей строке, вам все равно не нужно делать два отдельных прогона, просто используйте |
Это выражение ((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))
может обрабатывать практически каждый сценарий в книге
>>> 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'
Все зависит от того, что вы хотите, чтобы использовать решение, которое наилучшим образом соответствует вашим потребностям, поскольку оно не должно быть чрезмерно сложным.
NJoy!
Я предпочитаю избегать re, если это возможно:
myString="ThisStringIsCamelCase"
''.join(['_'+i.lower() if i.isupper() else i for i in myString]).lstrip('_')
'this_string_is_camel_case'
На всякий случай кому-то нужно преобразовать полный исходный файл, вот скрипт, который это сделает.
# 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))
Не в стандартной библиотеке, но я нашел этот скрипт , который, как представляется, содержит нужные вам функции.
Так много сложных методов ... Просто найдите все группы с названием «Названия» и присоединитесь к нижнему варианту с обложкой с подчеркиванием.
>>> 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'
Если вы не хотите, чтобы цифры, такие как первый символ группы или отдельная группа - вы можете использовать маску ([A-z][a-z0-9]*)
.