104 lines
6.0 KiB
Python
104 lines
6.0 KiB
Python
import json
|
||
import re
|
||
|
||
def transform_json(data):
|
||
result = {}
|
||
temp = {0: result} # 初始化根字典
|
||
|
||
# 首先,创建一个临时字典用于检查是否存在三级标题
|
||
has_subkey = {}
|
||
for key in data.keys():
|
||
parts = key.split('.')
|
||
if len(parts) > 2 and parts[1]:
|
||
parent_key = parts[0] + '.' + parts[1]
|
||
has_subkey[parent_key] = True
|
||
|
||
for key, value in data.items():
|
||
match = re.match(r'(\d+)(?:\.(\d+))?(?:\.(\d+))?', key)
|
||
if match:
|
||
levels = [int(l) for l in match.groups() if l is not None]
|
||
if (len(levels) - 1) in temp:
|
||
parent = temp[len(levels) - 1]
|
||
else:
|
||
print(f"No parent found at level {len(levels) - 1} for key '{key}'. Check the data structure.")
|
||
continue
|
||
|
||
if len(levels) == len(match.groups()):
|
||
if isinstance(parent, list):
|
||
parent.append(value)
|
||
else:
|
||
# 对于根级别,使用完整的值作为键
|
||
if len(levels) == 1:
|
||
parent[value] = {}
|
||
temp[len(levels)] = parent[value]
|
||
else:
|
||
parent[value.split()[0]] = value
|
||
else:
|
||
new_key = value
|
||
if '\n' in value and len(levels) == 2 and f"{levels[0]}.{levels[1]}" not in has_subkey:
|
||
new_key, new_value = value.split('\n', 1)
|
||
new_key = new_key.strip()
|
||
new_value = new_value.strip()
|
||
if isinstance(parent, list):
|
||
if len(parent) == 0 or not isinstance(parent[-1], dict):
|
||
parent.append({})
|
||
parent[-1][new_key] = new_value
|
||
else:
|
||
parent[new_key] = new_value
|
||
else:
|
||
if isinstance(parent, list):
|
||
if len(parent) == 0 or not isinstance(parent[-1], dict):
|
||
parent.append({})
|
||
parent = parent[-1]
|
||
if new_key not in parent:
|
||
parent[new_key] = []
|
||
temp[len(levels)] = parent[new_key]
|
||
|
||
def remove_single_item_lists(node):
|
||
if isinstance(node, dict):
|
||
for key in list(node.keys()):
|
||
node[key] = remove_single_item_lists(node[key])
|
||
if isinstance(node[key], list) and not node[key]:
|
||
node[key] = ""
|
||
elif isinstance(node, list) and len(node) == 1:
|
||
return remove_single_item_lists(node[0])
|
||
return node
|
||
|
||
return remove_single_item_lists(result)
|
||
|
||
# 示例 JSON 数据
|
||
data = {
|
||
"3.1": "投标文件的组成",
|
||
"3.1.1": "投标文件应包括下列内容:(1)投标函及投标函附录;(2)法定代表人身份证明;(3)联合体协议书(如有);(4)投标保证金;(5)监理服务费投标报价表;(6)监理大纲;(7)监理机构;(8)资格审查资料;(9)投标人须知前附表规定的其他材料。",
|
||
"3.1.2": "招标公告规定不接受联合体投标的,或投标人没有组成联合体的,投标文件不包括本章第3.1.1项第(3)目所指的联合体协议书。",
|
||
"3.1.3": "投标人须知前附表规定不允许分包的,投标文件不包括本章第3.1.1项第(8)目所指的拟分包项目情况表。",
|
||
"3.6": "投标文件的编制",
|
||
"3.6.1": "投标文件应按“投标文件格式”进行编写,如有必要,可以增加附页,作为投标文件的组成部分。其中,投标函附录在满足招标文件实质性要求的基础上,可以提出比招标文件要求更有利于招标人的承诺。",
|
||
"4.": "投标",
|
||
"4.1": "投标文件的密封与标记",
|
||
"4.1.1": "投标文件的加密加密的电子投标文件应按照本章第3.6.3项要求制作并加密,未按要求加密的电子投标文件,招标人(“市电子交易平台”)将拒收并提示。",
|
||
"4.1.2": "不加密的电子投标文件的密封和标识(1)不加密的电子投标文件(U盘备份)应单独密封包装,并在封套的封口处加贴封条。(2)不加密的电子投标文件(U盘备份)封套上应写明的其他内容见投标人须知前附表。3未按本章第4.1.2项要求密封和加写标记的投标文件,招标人将拒收。",
|
||
"4.2": "投标文件的递交",
|
||
"4.2.1": "在招标公告规定的投标截止时间前,投标人可以修改或撤回已递交的投标文件。",
|
||
"4.2.2": "投标人对加密的电子投标文件进行撤回的,在“市电子交易平台”直接进行撤回操作;投标人对不加密的电子投标文件(U盘备份)进行撤回的,应以书面形式通知招标人,撤回的书面通知应加盖投标人的单位章或由法定代表人或其委托代理人签字(指亲笔签名),招标人收到书面通知后,向投标人出具签收凭证。",
|
||
"4.3": "投标文件的修改与撤回",
|
||
"4.3.1": "在送交投标文件截止期以前,投标人可以更改或撤回投标文件,并按本章第项的规定操作。",
|
||
"4.3.2": "送交投标文件截止期以后,投标文件不得更改。需对投标文件做出澄清时,必须按照本须知第23条的规定办理。",
|
||
"4.3.4": "如果在送交投标文件截止期以后且投标文件有效期内撤回投标文件,则按本须知第3.4.4款的规定不予退还其投标担保。",
|
||
}
|
||
def sort_data_keys(data):
|
||
# 将键转换成由整数构成的元组,作为排序依据
|
||
def key_func(key):
|
||
return tuple(int(part) for part in re.split(r'\D+', key) if part)
|
||
# 对字典键进行排序
|
||
sorted_keys = sorted(data.keys(), key=key_func)
|
||
# 创建一个新的字典,按照排序后的键添加键值对
|
||
sorted_data = {key: data[key] for key in sorted_keys}
|
||
return sorted_data
|
||
|
||
sorted_data=sort_data_keys(data)
|
||
# 调用 transform_json 函数
|
||
transformed_data = transform_json(sorted_data)
|
||
|
||
# 打印结果
|
||
print(json.dumps(transformed_data, indent=4, ensure_ascii=False)) |