我编写了下面的函数,它将下划线转换为camelcase,第一个单词为小写,即“get_this_value” - > “getThisValue”。我还要求保留前导和尾随下划线以及双重(三重等)下划线,如果有的话,即
"_get__this_value_" -> "_get_ThisValue_".
代码:
def underscore_to_camelcase(value):
output = ""
first_word_passed = False
for word in value.split("_"):
if not word:
output += "_"
continue
if first_word_passed:
output += word.capitalize()
else:
output += word.lower()
first_word_passed = True
return output
我感觉上面的代码是以非Pythonic风格编写的,虽然它按预期工作,所以看看如何简化代码并使用列表推导等编写它。
答案 0 :(得分:41)
除了将第一个单词保留为小写之外,这个有效。
def convert(word):
return ''.join(x.capitalize() or '_' for x in word.split('_'))
(我知道这不是你要求的,这个帖子已经很老了,但是因为在Google上搜索这样的转换时它非常突出我以为我会添加我的解决方案,以防它帮助其他人)
答案 1 :(得分:29)
你的代码很好。我认为你要解决的问题是if first_word_passed
看起来有点难看。
解决此问题的一个选择是生成器。我们可以轻松地将此返回一个用于第一个条目,另一个用于所有后续条目。由于Python具有一流的功能,我们可以让生成器返回我们想要用来处理每个单词的函数。
然后我们只需要使用the conditional operator,这样我们就可以处理列表解析中双下划线返回的空白条目。
因此,如果我们有一个单词,我们调用生成器来获取用于设置大小写的函数,如果我们不这样做,我们只使用_
保持生成器不受影响。
def underscore_to_camelcase(value):
def camelcase():
yield str.lower
while True:
yield str.capitalize
c = camelcase()
return "".join(c.next()(x) if x else '_' for x in value.split("_"))
答案 2 :(得分:18)
我个人更喜欢正则表达式。这是为我做的诀窍:
import re
def to_camelcase(s):
return re.sub(r'(?!^)_([a-zA-Z])', lambda m: m.group(1).upper(), s)
使用unutbu
的测试:
tests = [('get__this_value', 'get_ThisValue'),
('_get__this_value', '_get_ThisValue'),
('_get__this_value_', '_get_ThisValue_'),
('get_this_value', 'getThisValue'),
('get__this__value', 'get_This_Value')]
for test, expected in tests:
assert to_camelcase(test) == expected
答案 3 :(得分:7)
这是一个更简单的。可能并不适合所有情况,但它符合我的要求,因为我只是将具有特定格式的python变量转换为驼峰式。除了第一个单词之外,这确实很有用。
def underscore_to_camelcase(text):
"""
Converts underscore_delimited_text to camelCase.
Useful for JSON output
"""
return ''.join(word.title() if i else word for i, word in enumerate(text.split('_')))
答案 4 :(得分:3)
我认为代码很好。你有一个相当复杂的规范,所以如果你坚持将它压缩到列表理解的Procrustean床上,那么你可能会损害代码的清晰度。
我所做的唯一改变是:
join
方法在O( n )空间和时间中构建结果,而不是重复+=
的应用程序,即O( n ²)。像这样:
def underscore_to_camelcase(s):
"""Take the underscore-separated string s and return a camelCase
equivalent. Initial and final underscores are preserved, and medial
pairs of underscores are turned into a single underscore."""
def camelcase_words(words):
first_word_passed = False
for word in words:
if not word:
yield "_"
continue
if first_word_passed:
yield word.capitalize()
else:
yield word.lower()
first_word_passed = True
return ''.join(camelcase_words(s.split('_')))
根据应用程序的不同,我会考虑进行另一项更改,即记住该功能。我假设您以某种方式自动翻译源代码,并且您希望多次出现相同的名称。所以你不妨存储转换,而不是每次都重新计算它。一种简单的方法是使用Python decorator library中的@memoized
装饰器。
答案 5 :(得分:3)
该算法在数字上表现良好:
import re
PATTERN = re.compile(r'''
(?<!\A) # not at the start of the string
_
(?=[a-zA-Z]) # followed by a letter
''', re.X)
def camelize(value):
tokens = PATTERN.split(value)
response = tokens.pop(0).lower()
for remain in tokens:
response += remain.capitalize()
return response
示例:
>>> camelize('Foo')
'foo'
>>> camelize('_Foo')
'_foo'
>>> camelize('Foo_')
'foo_'
>>> camelize('Foo_Bar')
'fooBar'
>>> camelize('Foo__Bar')
'foo_Bar'
>>> camelize('9')
'9'
>>> camelize('9_foo')
'9Foo'
>>> camelize('foo_9')
'foo_9'
>>> camelize('foo_9_bar')
'foo_9Bar'
>>> camelize('foo__9__bar')
'foo__9_Bar'
答案 6 :(得分:2)
我同意Gareth认为代码没问题。但是,如果你真的想要一个更简短但可读的方法,你可以尝试这样的事情:
def underscore_to_camelcase(value):
# Make a list of capitalized words and underscores to be preserved
capitalized_words = [w.capitalize() if w else '_' for w in value.split('_')]
# Convert the first word to lowercase
for i, word in enumerate(capitalized_words):
if word != '_':
capitalized_words[i] = word.lower()
break
# Join all words to a single string and return it
return "".join(capitalized_words)
答案 7 :(得分:2)
该问题需要一个第一次返回小写单词的函数,但之后会返回大写单词。您可以使用if
子句执行此操作,但必须针对每个单词评估if
子句。一个有吸引力的替代方案是使用发电机。它可以在第一次调用时返回一个东西,在连续调用时返回其他内容,并且它不需要if
个。{/ p>
def lower_camelcase(seq):
it=iter(seq)
for word in it:
yield word.lower()
if word.isalnum(): break
for word in it:
yield word.capitalize()
def underscore_to_camelcase(text):
return ''.join(lower_camelcase(word if word else '_' for word in text.split('_')))
以下是一些测试代码,表明它有效:
tests=[('get__this_value','get_ThisValue'),
('_get__this_value','_get_ThisValue'),
('_get__this_value_','_get_ThisValue_'),
('get_this_value','getThisValue'),
('get__this__value','get_This_Value'),
]
for test,answer in tests:
result=underscore_to_camelcase(test)
try:
assert result==answer
except AssertionError:
print('{r!r} != {a!r}'.format(r=result,a=answer))
答案 8 :(得分:1)
这是列表理解样式生成器表达式。
from itertools import count
def underscore_to_camelcase(value):
words = value.split('_')
counter = count()
return ''.join('_' if w == '' else w.capitalize() if counter.next() else w for w in words )
答案 9 :(得分:1)
这是我的,主要依靠列表理解,分裂和加入。加上可选参数使用不同的分隔符:
def underscore_to_camel(in_str, delim="_"):
chunks = in_str.split(delim)
chunks[1:] = [_.title() for _ in chunks[1:]]
return "".join(chunks)
另外,为了完整起见,包括之前作为反向解释的另一个问题的解决方案(不是我自己的代码,只是重复以便于参考):
first_cap_re = re.compile('(.)([A-Z][a-z]+)')
all_cap_re = re.compile('([a-z0-9])([A-Z])')
def camel_to_underscore(in_str):
s1 = first_cap_re.sub(r'\1_\2', name)
return all_cap_re.sub(r'\1_\2', s1).lower()
答案 10 :(得分:0)
这是最简洁的方法:
def underscore_to_camelcase(value):
words = [word.capitalize() for word in value.split('_')]
words[0]=words[0].lower()
return "".join(words)
答案 11 :(得分:0)
为了regexp!
import re
def underscore_to_camelcase(value):
def rep(m):
if m.group(1) != None:
return m.group(2) + m.group(3).lower() + '_'
else:
return m.group(3).capitalize()
ret, nb_repl = re.subn(r'(^)?(_*)([a-zA-Z]+)', rep, value)
return ret if (nb_repl > 1) else ret[:-1]
答案 12 :(得分:0)
另一种正则表达式解决方案:
import re
def conv(s):
"""Convert underscore-separated strings to camelCase equivalents.
>>> conv('get')
'get'
>>> conv('_get')
'_get'
>>> conv('get_this_value')
'getThisValue'
>>> conv('__get__this_value_')
'_get_ThisValue_'
>>> conv('_get__this_value__')
'_get_ThisValue_'
>>> conv('___get_this_value')
'_getThisValue'
"""
# convert case:
s = re.sub(r'(_*[A-Z])', lambda m: m.group(1).lower(), s.title(), count=1)
# remove/normalize underscores:
s = re.sub(r'__+|^_+|_+$', '|', s).replace('_', '').replace('|', '_')
return s
if __name__ == "__main__":
import doctest
doctest.testmod()
它适用于您的示例,但对于包含数字的名称可能会失败 - 这取决于您如何将它们大写。
答案 13 :(得分:0)
稍加修改的版本:
import re
def underscore_to_camelcase(value):
first = True
res = []
for u,w in re.findall('([_]*)([^_]*)',value):
if first:
res.append(u+w)
first = False
elif len(w)==0: # trailing underscores
res.append(u)
else: # trim an underscore and capitalize
res.append(u[:-1] + w.title())
return ''.join(res)
答案 14 :(得分:0)
我知道这已经得到了解答,但我想出了一些语法糖来处理一个特殊情况,所选择的答案没有(带有dunders的词,即&#34; my_word__is _____丑陋&#34;到&#34; myWordIsUgly&#34)。显然,这可以分解成多行,但我喜欢将它放在一个上面的挑战。为清晰起见,我添加了换行符。
def underscore_to_camel(in_string):
return "".join(
list(
map(
lambda index_word:
index_word[1].lower() if index_word[0] == 0
else index_word[1][0].upper() + (index_word[1][1:] if len(index_word[1]) > 0 else ""),
list(enumerate(re.split(re.compile(r"_+"), in_string)
)
)
)
)
)
答案 15 :(得分:0)
def convert(word):
if not isinstance(word, str):
return word
if word.startswith("_"):
word = word[1:]
words = word.split("_")
_words = []
for idx, _word in enumerate(words):
if idx == 0:
_words.append(_word)
continue
_words.append(_word.capitalize())
return ''.join(_words)