在JSON序列化/反序列化期间转换camelCase和下划线之间的标识符命名

tam*_*are 15 python json

我正在开发一个python/django应用程序,作为其前端对应的Web API服务器.服务器和客户端之间的数据交换采用JSON格式,使用XMLHttpRequest(Javascript).对于那些熟悉Python和Javascript的人,你知道他们在变量/方法/属性方面有不同的标识符命名约定; Python使用,names_with_underscores而Javascript更喜欢camelCaseNames.我想在各自的世界中保留这两个约定,并在数据交换发生时执行标识符的转换.

我决定在服务器上执行转换(Python).在我看来,这种双向转换最合乎逻辑的地方是在JSON序列化/反序列化期间.我该如何实施这种方法?例子受到高度赞赏.

请注意,我使用的是Python 2.7.

Jar*_*red 18

使用正则表达式的一种方法,

import re

camel_pat = re.compile(r'([A-Z])')
under_pat = re.compile(r'_([a-z])')

def camel_to_underscore(name):
    return camel_pat.sub(lambda x: '_' + x.group(1).lower(), name)

def underscore_to_camel(name):
    return under_pat.sub(lambda x: x.group(1).upper(), name)
Run Code Online (Sandbox Code Playgroud)

和,

>>> camel_to_underscore('camelCaseNames')
'camel_case_names'
>>> underscore_to_camel('names_with_underscores')
'namesWithUnderscores'
Run Code Online (Sandbox Code Playgroud)

注意:您必须使用函数(lambda此处为表达式)来完成大小写更改,但这看起来非常简单.

编辑:

如果你真的想在Python和Javascript之间拦截和调整json对象,你将不得不重写json模块的功能.但我认为这比它的价值更麻烦.相反,像这样的东西是等价的,而不是太明显的性能.

要转换dict代表你的json对象的每个键,你可以做这样的事情,

def convert_json(d, convert):
    new_d = {}
    for k, v in d.iteritems():
        new_d[convert(k)] = convert_json(v,convert) if isinstance(v,dict) else v
    return new_d
Run Code Online (Sandbox Code Playgroud)

您只需提供要应用的功能,

>>> json_obj = {'nomNom': {'fooNom': 2, 'camelFoo': 3}, 'camelCase': {'caseFoo': 4, 'barBar': {'fooFoo': 44}}}
>>> convert_json(json_obj, camel_to_underscore)
{'nom_nom': {'foo_nom': 2, 'camel_foo': 3}, 'camel_case': {'case_foo': 4, 'bar_bar': {'foo_foo': 44}}}
Run Code Online (Sandbox Code Playgroud)

你可以将所有这些逻辑包装在新的loaddump函数中,

import json

def convert_load(*args, **kwargs):
    json_obj = json.load(*args, **kwargs)
    return convert_json(json_obj, camel_to_underscore)

def convert_dump(*args, **kwargs):
    args = (convert_json(args[0], underscore_to_camel),) + args[1:]
    json.dump(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

然后使用就像你json.loadjson.dump.


Eva*_*oky 12

Jared的回答没有考虑json对象结构中带有对象的数组的可能性.

该解决方案需要三个函数来递归处理数组.

从CamelCase转换为underscores_with_spaces:

def convert(s):
    a = re.compile('((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))')
    return a.sub(r'_\1', s).lower()
Run Code Online (Sandbox Code Playgroud)

对于json对象

def convertJSON(j):
    out = {}
    for k in j:
        newK = convert(k)
        if isinstance(j[k],dict):
            out[newK] = convertJSON(j[k])
        elif isinstance(j[k],list):
            out[newK] = convertArray(j[k])
        else:
            out[newK] = j[k]
    return out
Run Code Online (Sandbox Code Playgroud)

对于json对象中的数组:

def convertArray(a):
    newArr = []
    for i in a:
        if isinstance(i,list):
            newArr.append(convertArray(i))
        elif isinstance(i, dict):
            newArr.append(convertJSON(i))
        else:
            newArr.append(i)
    return newArr
Run Code Online (Sandbox Code Playgroud)

用法:

convertJSON({
    "someObject": [
        {
            "anotherObject": "CamelCaseValue"
        },
        {
            "anotherObject": "AnotherCamelCaseValue"
        }
    ]
})
Run Code Online (Sandbox Code Playgroud)

产量:

{
    'some_object': [
        {
            'another_object': 'CamelCaseValue'
        },
        {
            'another_object': 'AnotherCamelCaseValue'
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)


Fus*_*ush 7

对于未来的 googlers,该humps软件包可以为您完成此操作。

import humps
humps.decamelize({'outerKey': {'innerKey': 'value'}})
# {'outer_key': {'inner_key': 'value'}}
Run Code Online (Sandbox Code Playgroud)