如何把 Java properties 转换为具有层级结构的字典

2021-08-24 09:47:13 +08:00
 MiketsuSmasher
java.class.version = 60.0
java.home = /usr/lib/jvm/java-16-openjdk
java.runtime.name = OpenJDK Runtime Environment
java.runtime.version = 16.0.2+7
java.specification.name = Java Platform API Specification
java.specification.vendor = Oracle Corporation
java.specification.version = 16
java.vendor = N/A
java.vendor.url = https://openjdk.java.net/
java.vendor.url = https://openjdk.java.net/
java.vendor.url.bug = https://bugreport.java.com/bugreport/
java.vendor.url.bug = https://bugreport.java.com/bugreport/
java.vendor.url.bug = https://bugreport.java.com/bugreport/
java.version = 16.0.2
java.version.date = 2021-07-20
java.vm.name = OpenJDK 64-Bit Server VM
java.vm.specification.name = Java Virtual Machine Specification
java.vm.specification.vendor = Oracle Corporation
java.vm.specification.version = 16
java.vm.vendor = Oracle Corporation
java.vm.version = 16.0.2+7
sun.arch.data.model = 64

我用 javaproperties 模块把上面内容转换成了字典:

{'java.class.version': '60.0',
 'java.home': '/usr/lib/jvm/java-16-openjdk',
 'java.runtime.name': 'OpenJDK Runtime Environment',
 'java.runtime.version': '16.0.2+7',
 'java.specification.name': 'Java Platform API Specification',
 'java.specification.vendor': 'Oracle Corporation',
 'java.specification.version': '16',
 'java.vendor': 'N/A',
 'java.vendor.url': 'https://openjdk.java.net/',
 'java.vendor.url.bug': 'https://bugreport.java.com/bugreport/',
 'java.version': '16.0.2',
 'java.version.date': '2021-07-20',
 'java.vm.name': 'OpenJDK 64-Bit Server VM',
 'java.vm.specification.name': 'Java Virtual Machine Specification',
 'java.vm.specification.vendor': 'Oracle Corporation',
 'java.vm.specification.version': '16',
 'java.vm.vendor': 'Oracle Corporation',
 'java.vm.version': '16.0.2+7',
 'sun.arch.data.model': '64'}

但是我想根据这些 properties 的键中相同的部分,把它转换成具有层级结构的字典,类似于:

{
    'java': {
        'class': {
            'version': 60.0
        },
        'home': '/usr/lib/jvm/java-16-openjdk',
        'runtime': {
            'name': 'OpenJDK Runtime Environment',
            'version': '16.0.2+7'
        },
        'specification': {
            'name': 'Java Platform API Specification',
            'vendor': 'Oracle Corporation',
            'verison': 16
        },
        ...: ...  # 省略剩余的内容
    },
    'sun': {
        'arch': {
            'data': {
                'model': 64
            }
        }
    }
}

有没有第三方库方便进行转换?或者如果自己造轮子,提供一个思路?

2572 次点击
所在节点    Python
27 条回复
O5oz6z3
2021-08-24 18:53:13 +08:00
有点麻烦,`java.vendor = N/A` 有子节点,`java.vendor.url = ……/openjdk.java.net/` 有复数行。
如果不考虑那么多,贡献一个 py 大致思路,不保证对:用 configparser 读取 ini 格式的数据变成字典(有个参数允许同键名的复数行),遍历字典(for key, value in dict.items()),将键名按点分割(key.split(".")),遍历分割后键名的每个层级,用 dict.setdefault(parentkey, dict())初始化每个层级,最后赋值。
最近在哪见过类似的格式,不过想不起来了。
MiketsuSmasher
2021-08-24 19:14:09 +08:00
@O5oz6z3 可以通过转换 java.vendor 为{'java': 'vendor': {'': 'N/A', 'url': ...}解决。
至于重复行的问题,反正都是一样的,保留一行就好了。
xuanbg
2021-08-24 20:23:43 +08:00
对象序列化成 json,json 再反序列化成 map 就好了。
O5oz6z3
2021-08-24 21:30:50 +08:00
@MiketsuSmasher #22 好主意,我看到过 setuptools 也是用这种写法
zhoudaiyu
2021-08-25 13:13:24 +08:00
Python 简单搞了一下,不支持这种不满足 json 定义的格式的,比如'java.vendor.url': 'https://openjdk.java.net/' 和 'java.vendor.url.bug': 'https://bugreport.java.com/bugreport/'
```py
import re
import json


ori = """{'java.class.version': '60.0',
'java.home': '/usr/lib/jvm/java-16-openjdk',
'java.runtime.name': 'OpenJDK Runtime Environment',
'java.runtime.version': '16.0.2+7',
'java.specification.name': 'Java Platform API Specification',
'java.specification.vendor': 'Oracle Corporation',
'java.specification.version': '16',
'java.vendor.url.bug.b': 'https://bugreport.java.com/bugreport/',
'java.version.date': '2021-07-20',
'java.vm.name': 'OpenJDK 64-Bit Server VM',
'java.vm.specification.name': 'Java Virtual Machine Specification',
'java.vm.specification.vendor': 'Oracle Corporation',
'java.vm.specification.version': '16',
'java.vm.vendor': 'Oracle Corporation',
'java.vm.version': '16.0.2+7',
'sun.arch.data.model': '64'}"""


prop_regex = re.compile("'(?P<key>.*)':\s*'(?P<value>.*)'\s*")


def dict_filter(dic: dict, _str: str) -> dict:
ret_dict = dict()
for k in dic.keys():
if k != _str:
ret_dict[k] = dic[k]
return ret_dict


def get_deepest_dict(dic: dict, keys: list) -> dict:
_dic = dict()
_dic = dic
for i in keys:
_dic = _dic[i]
return _dic


def prop2json_converter(src_str: str) -> str:
"""
Convert property string to json string.
:param src_str: source property string
:return: a wrapped json string
"""
try:
_dict = dict()
ret_dict = dict()
for ln in src_str.split("\n"):
matched_k_v = prop_regex.search(ln)
if matched_k_v:
_dict[matched_k_v.groupdict().get("key")] = matched_k_v.groupdict().get("value")
for k, v in _dict.items():
for cnt, kk in enumerate(k.split(".")):
_l = k.split(".")[:cnt]
if cnt != len(k.split(".")) - 1:
if not _l:
ret_dict.setdefault(kk, dict())
else:
_r = get_deepest_dict(ret_dict, _l)
_r.setdefault(kk, dict())

else:
if not _l:
ret_dict.setdefault(kk, v)
else:
_r = get_deepest_dict(ret_dict, _l)
_r[kk] = v

except (TypeError, AttributeError):
return json.dumps({"data": None, "err": "Invalid input string"}, ensure_ascii=False, indent=4)
return json.dumps({"data": ret_dict, "err": ""}, ensure_ascii=False, indent=4)


if __name__ == '__main__':
print(prop2json_converter(ori))
zhoudaiyu
2021-08-25 13:17:32 +08:00
@zhoudaiyu #25 为啥不支持 markdown....换下 gist....https://gist.github.com/BiTree/f21adc0e6ce67c18784690dfbaf15af8
zhoudaiyu
2021-08-25 13:19:41 +08:00
@zhoudaiyu #26 忽略 dict_filter 这个方法,没有引用忘了删了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/797618

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX