例子:

>>> convert('CamelCase')
'camel_case'

当前回答

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()

其他回答

这个简单的方法应该可以做到:

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()

我们寻找前面有任意数量的(或零)大写字母,后面有任意数量的小写字符的大写字母。 在组中发现的最后一个大写字母之前放置下划线,如果前面有其他大写字母,则可以在该大写字母之前放置下划线。 如果后面有下划线,删除它们。 最后,整个结果字符串被改为小写。

(从这里开始,见在线工作示例)

以防有人需要转换一个完整的源文件,这里有一个脚本可以做到这一点。

# 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))

下面是我更改制表符分隔的文件头部的一些操作。我省略了只编辑文件第一行的部分。你可以用re库很容易地将它适应Python。这还包括分离数字(但保持数字在一起)。我分两步完成,因为这比告诉它不要在行或制表符的开头放下划线更容易。

第一步……查找大写字母或小写字母前面的整数,并在它们前面加下划线:

搜索:

([a-z]+)([A-Z]|[0-9]+)

替换:

\1_\l\2/

第二步……使用上面的代码并再次运行它,将所有大写字母转换为小写字母:

搜索:

([A-Z])

替换(即反斜杠,小写L,反斜杠,1):

\l\1

一个使用正则表达式的可怕例子(你可以很容易地清理:)):

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")

但适用于getHTTPResponseCode !

或者,使用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")

编辑:对于像“Test”这样的情况,应该也很容易看到有改进的空间,因为下划线是无条件插入的。

我不知道为什么使用两个.sub()调用?:)我不是正则表达式大师,但我简化了这个函数,这是适合我的特定需求,我只是需要一个解决方案,将camelCasedVars从POST请求转换为vars_with_下划线:

def myFunc(...):
  return re.sub('(.)([A-Z]{1})', r'\1_\2', "iTriedToWriteNicely").lower()

它不能使用像getHTTPResponse这样的名字,因为我听说这是一个糟糕的命名惯例(应该像getHTTPResponse一样,很明显,它更容易记住这个形式)。