148 lines
5.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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