143 lines
7.9 KiB
Python
143 lines
7.9 KiB
Python
import json
|
||
import re
|
||
from functools import cmp_to_key
|
||
|
||
|
||
def compare_headings(a, b):
|
||
a_nums = [int(num) for num in a[0].rstrip('.').split('.') if num.isdigit()]
|
||
b_nums = [int(num) for num in b[0].rstrip('.').split('.') if num.isdigit()]
|
||
return (a_nums > b_nums) - (a_nums < b_nums)
|
||
|
||
|
||
def preprocess_data(data):
|
||
"""
|
||
预处理数据,自动添加缺失的父层级键,并按数字顺序排序。
|
||
"""
|
||
keys_to_add = set()
|
||
for key in data.keys():
|
||
parts = key.split('.')
|
||
if len(parts) > 1:
|
||
parent_key = parts[0] + '.'
|
||
if parent_key not in data:
|
||
keys_to_add.add(parent_key)
|
||
|
||
# 添加缺失的父层级键
|
||
for parent_key in keys_to_add:
|
||
data[parent_key] = parent_key.rstrip('.')
|
||
|
||
# 对键进行排序
|
||
sorted_data = dict(sorted(data.items(), key=cmp_to_key(compare_headings)))
|
||
|
||
return sorted_data
|
||
|
||
def transform_json(data):
|
||
result = {}
|
||
temp = {0: result} # 初始化根字典
|
||
data=preprocess_data(data)
|
||
print(json.dumps(data,ensure_ascii=False,indent=4))
|
||
# 首先,创建一个临时字典用于检查是否存在三级标题
|
||
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) == 1: # 一级标题
|
||
# 新增逻辑:判断值中是否有 ':' 或 ':',并进行拆分
|
||
# 优先按 '\n' 拆分
|
||
if '\n' in value:
|
||
new_key, *new_value = value.split('\n', 1)
|
||
new_key = new_key.strip()
|
||
new_value = new_value[0].strip() if new_value else ""
|
||
# 如果没有 '\n',再检查 ':' 或 ':',并进行拆分
|
||
elif ':' in value or ':' in value:
|
||
delimiter = ':' if ':' in value else ':'
|
||
new_key, new_value = value.split(delimiter, 1)
|
||
new_key = new_key.strip()
|
||
new_value = new_value.strip()
|
||
else:
|
||
new_key = value.strip()
|
||
new_value = ""
|
||
|
||
parent[new_key] = {}
|
||
if new_value:
|
||
parent[new_key][new_key] = new_value # 使用 new_key 作为键名,而不是固定的 "content"
|
||
temp[len(levels)] = parent[new_key]
|
||
elif len(levels) == 2: # 二级标题
|
||
new_key, *new_value = value.split('\n', 1)
|
||
new_key = new_key.strip()
|
||
new_value = new_value[0].strip() if new_value else ""
|
||
|
||
if f"{levels[0]}.{levels[1]}" in has_subkey:
|
||
parent[new_key] = [new_value] if new_value else []
|
||
else:
|
||
parent[new_key] = new_value
|
||
|
||
temp[len(levels)] = parent[new_key]
|
||
else: # 三级标题
|
||
if isinstance(parent, dict):
|
||
parent_key = list(parent.keys())[-1]
|
||
if isinstance(parent[parent_key], list):
|
||
parent[parent_key].append(value)
|
||
elif parent[parent_key]:
|
||
parent[parent_key] = [parent[parent_key], value]
|
||
else:
|
||
parent[parent_key] = [value]
|
||
elif isinstance(parent, list):
|
||
parent.append(value)
|
||
|
||
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 len(node[key]) == 1:
|
||
node[key] = node[key][0]
|
||
return node
|
||
|
||
return remove_single_item_lists(result)
|
||
|
||
# 示例数据
|
||
data = {
|
||
"10.1": "投标人提交的投标文件以及投标人与招标采购单位就有关投标的所有来往函电均应使用中文书写。投标人提交的支持资料和己印刷的文献可以用另一种语言,但相应内容应附有中文翻译本,在解释投标文件的修改内容时以中文翻译本为准。对中文翻译有异议的,以权威机构的译本为准。11投标文件的构成",
|
||
"11.1": "投标人编写的投标文件应包括价格文件、技术文件、商务文件,价格部分必须独立装订,编排顺序参见投标文件格式。",
|
||
"11.2": "投标文件的构成应符合法律法规及招标文件的要求。12投标文件的编写",
|
||
"12.1": "投标人应完整、真实、准确地填写招标文件中提供的投标函、投标报价一览表、投标明细报价表(如适用)以及招标文件中规定的其它所有内容。",
|
||
"12.2": "投标人对招标文件中多个包组进行投标的,其投标文件的编制可按每个包组的要求分别装订和封装。投标人应当对投标文件进行装订,对未经装订的投标文件可能发生的文件散落或缺损,由此造成的后果和责任由投标人承担。",
|
||
"12.3": "投标人必须对投标文件所提供的全部资料的真实性承担法律责任,并无条件接受招标采购单位及政府采购监督管理部门等对其中任何资料进行核实的要求。",
|
||
"12.4": "如果因为投标人的投标文件只填写和提供了本招标文件要求的部分内容和附件,或没有提供招标文件中所要求的全部资料及数据,由此造成的后果和责任由投标人承担。13投标报价",
|
||
# 可能缺失的父层级键
|
||
# "10.": "投标文件相关内容", # 示例父层级,实际可能缺失
|
||
# "11.": "投标文件的构成",
|
||
# "12.": "投标文件的编写",
|
||
# "13.": "投标报价"
|
||
}
|
||
|
||
tran={
|
||
"10.": "10",
|
||
"10.1": "投标人提交的投标文件以及投标人与招标采购单位就有关投标的所有来往函电均应使用中文书写。投标人提交的支持资料和己印刷的文献可以用另一种语言,但相应内容应附有中文翻译本,在解释投标文件的修改内容时以中文翻译本为准。对中文翻译有异议的,以权威机构的译本为准。11投标文件的构成",
|
||
"11.": "11",
|
||
"11.1": "投标人编写的投标文件应包括价格文件、技术文件、商务文件,价格部分必须独立装订,编排顺序参见投标文件格式。",
|
||
"11.2": "投标文件的构成应符合法律法规及招标文件的要求。12投标文件的编写",
|
||
"12.": "12",
|
||
"12.1": "投标人应完整、真实、准确地填写招标文件中提供的投标函、投标报价一览表、投标明细报价表(如适用)以及招标文件中规定的其它所有内容。",
|
||
"12.2": "投标人对招标文件中多个包组进行投标的,其投标文件的编制可按每个包组的要求分别装订和封装。投标人应当对投标文件进行装订,对未经装订的投标文件可能发生的文件散落或缺损,由此造成的后果和责任由投标人承担。",
|
||
"12.3": "投标人必须对投标文件所提供的全部资料的真实性承担法律责任,并无条件接受招标采购单位及政府采购监督管理部门等对其中任何资料进行核实的要求。",
|
||
"12.4": "如果因为投标人的投标文件只填写和提供了本招标文件要求的部分内容和附件,或没有提供招标文件中所要求的全部资料及数据,由此造成的后果和责任由投标人承担。13投标报价",
|
||
}
|
||
data=preprocess_data(data)
|
||
print(json.dumps(data,ensure_ascii=False,indent=4))
|
||
# transformed = transform_json(tran)
|
||
# import pprint
|
||
# pprint.pprint(transformed)
|