148 lines
5.6 KiB
Python
Raw Normal View History

import json
import re
def generate_key_paths(data, parent_key='', good_list=None, seen=None):
"""
生成嵌套字典中的键路径并提取最内层的键名
同时提取特定模式的键 '交换机-1', '交换机-2'的父路径
如果同一层级下只有'交换机-1'但没有'交换机-2'则视为错误输入删除后缀'-1''交换机'加入key_paths
并从data中移除错误的键
参数:
data (dict): 输入的字典数据
parent_key (str): 上级键路径用于递归调用
good_list (list): 用于存储去重后的最内层键名
seen (set): 用于跟踪已添加到 good_list 的元素
返回:
tuple: 包含键路径列表最内层键名列表分组路径列表以及 no_keys_added 的元组
(key_paths, good_list, grouped_paths, no_keys_added)
"""
if good_list is None:
good_list = []
if seen is None:
seen = set()
key_paths = []
grouped_paths = set() # 使用集合避免重复路径
no_keys_added = True # 默认假设没有添加任何键
# Step 1: Collect keys that match the pattern
pattern = re.compile(r'(.+)-\d+$') # 匹配形如 '交换机-1', '交换机-2' 的键
prefix_groups = {}
other_keys = []
for key in list(data.keys()): # 使用 list(data.keys()) 防止修改字典时出错
clean_key = key.replace(" ", "")
match = pattern.match(clean_key)
if match:
prefix = match.group(1)
if prefix not in prefix_groups:
prefix_groups[prefix] = []
prefix_groups[prefix].append(key)
else:
other_keys.append(key)
# Step 2: Handle grouped keys
for prefix, keys in prefix_groups.items():
current_prefix_path = f"{parent_key}.{prefix}" if parent_key else prefix
if len(keys) > 1:
# 多个键匹配同一前缀:添加到 grouped_paths
grouped_paths.add(current_prefix_path)
if prefix not in seen:
good_list.append(prefix)
seen.add(prefix)
no_keys_added = False
else:
# 只有一个键匹配:删除后缀并添加到 key_paths同时从 data 中移除该键
key = keys[0]
key_path = current_prefix_path # 去掉后缀后,路径为父路径 + 前缀
key_paths.append(key_path)
if prefix not in seen:
good_list.append(prefix)
seen.add(prefix)
no_keys_added = False
# 从 data 中移除错误的键
data.pop(key)
# Step 3: Handle other keys
for key in other_keys:
value = data[key]
current_key = f"{parent_key}.{key}" if parent_key else key
if isinstance(value, dict):
if value:
# 递归调用,并获取子路径、子 good_list、子分组路径以及子 no_keys_added
sub_key_paths, _, sub_grouped_paths, sub_no_keys_added = generate_key_paths(
value, current_key, good_list, seen
)
key_paths.extend(sub_key_paths)
grouped_paths.update(sub_grouped_paths) # 合并子分组路径到当前分组路径
# 更新 no_keys_added
no_keys_added = no_keys_added and sub_no_keys_added
else:
# 空字典视为叶子节点
clean_key = key.replace(" ", "")
key_paths.append(current_key.replace(" ", ""))
if clean_key not in seen:
good_list.append(clean_key) # 去掉空格后添加
seen.add(clean_key)
# 更新 no_keys_added
no_keys_added = False
elif isinstance(value, list):
# 列表类型视为叶子节点,无论是否为空
key_paths.append(current_key.replace(" ", ""))
clean_key = key.replace(" ", "")
if clean_key not in seen:
good_list.append(clean_key) # 去掉空格后添加
seen.add(clean_key)
# 更新 no_keys_added
no_keys_added = False
elif value in {"未知", "", "/"}:
# 特定值视为叶子节点
key_paths.append(current_key.replace(" ", ""))
clean_key = key.replace(" ", "")
if clean_key not in seen:
good_list.append(clean_key) # 去掉空格后添加
seen.add(clean_key)
# 更新 no_keys_added
no_keys_added = False
else:
# 其他情况视为叶子节点
key_paths.append(current_key.replace(" ", ""))
clean_key = key.replace(" ", "")
if clean_key not in seen:
good_list.append(clean_key) # 去掉空格后添加
seen.add(clean_key)
# 更新 no_keys_added
no_keys_added = False
return key_paths, good_list, grouped_paths, no_keys_added
# 示例使用
data1 = {
"采购需求": {
"高清数字枪机-1": [],
"枪机支架-1": [],
"高清数字半球机-1": [],
"网络硬盘录像机-1": [],
"监硬控硬盘-1": [],
"交换机-1": [],
"交换机-2": [],
"监视器-1": [],
"电源线-1": [],
"网线-1": [],
"水晶头-1": [],
"PVC线槽-1": [],
"辅料-1": [],
"安装调试-1": [],
"视频图像采集及存储系统": {
"系统功能": []
}
}
}
key_paths, good_list, grouped_paths, no_keys_added = generate_key_paths(data1)
print(json.dumps(data1,ensure_ascii=False,indent=4))