import os import shutil import json import re from collections import defaultdict def extract_leading_digits(prefix): """提取前缀中最前面的连续数字,无数字则返回None""" match = re.match(r'^(\d+)', prefix) return match.group(1) if match else None def compare_json_and_prefixes(json_file_path): """对比JSON中的.dat键名和提取的前缀,找出差异""" try: print("\n" + "=" * 80) print("第一步:JSON键名与提取前缀对比分析") print("=" * 80) # 1. 读取JSON所有.dat键名 json_keys = [] with open(json_file_path, 'r', encoding='utf-8') as f: dat_mapping = json.load(f) for key in dat_mapping.keys(): key_stripped = key.strip() if key_stripped.endswith('.dat'): json_keys.append(key_stripped) total_json_keys = len(json_keys) print(f"1. 从JSON中读取到 {total_json_keys} 个.dat键名") # 2. 提取前缀并分析 extracted_prefixes = {} prefix_to_keys = defaultdict(list) # 记录前缀对应的所有键名 for key in json_keys: original_prefix = os.path.splitext(key)[0].strip() lower_prefix = original_prefix.lower() extracted_prefixes[lower_prefix] = original_prefix prefix_to_keys[lower_prefix].append(key) total_extracted = len(extracted_prefixes) print(f"2. 提取到 {total_extracted} 个唯一前缀") # 3. 分析差异原因 if total_extracted < total_json_keys: diff_count = total_json_keys - total_extracted print(f"\n⚠️ 发现差异:前缀数比JSON键名少 {diff_count} 个") print(" 原因:存在不同键名对应相同前缀的情况(如下所示)") # 显示前5个存在重复前缀的例子 duplicate_prefixes = {p: keys for p, keys in prefix_to_keys.items() if len(keys) > 1} print(f"\n 存在重复前缀的键名数量:{len(duplicate_prefixes)} 组") for i, (prefix, keys) in enumerate(list(duplicate_prefixes.items())[:5], 1): print(f" 示例 {i}: 前缀 '{prefix}' 对应 {len(keys)} 个键名 → {keys[:2]}...") else: print("\n✅ 前缀数与JSON键名数一致,无差异") return json_keys, prefix_to_keys except Exception as e: print(f"❌ 对比分析失败: {str(e)}") return [], {} def copy_obj_files(json_file_path, obj_source_dir, dest_dir, json_keys): """复制OBJ文件,基于JSON中的.dat键名""" try: print("\n" + "=" * 80) print("第二步:OBJ文件复制操作") print("=" * 80) # 1. 初始化目录 os.makedirs(dest_dir, exist_ok=True) print(f"📂 目标目录已准备:{dest_dir}") # 2. 预处理OBJ文件 obj_lower_to_info = {} for filename in os.listdir(obj_source_dir): if filename.lower().endswith('.obj'): obj_original_prefix = os.path.splitext(filename)[0].strip() obj_lower_prefix = obj_original_prefix.lower() obj_full_path = os.path.join(obj_source_dir, filename) obj_lower_to_info[obj_lower_prefix] = (obj_original_prefix, obj_full_path) print(f"🔍 已预处理 {len(obj_lower_to_info)} 个OBJ文件") # 3. 提取所有dat前缀(保留原始顺序) dat_prefixes = [os.path.splitext(key)[0].strip() for key in json_keys] print(f"📋 待匹配的dat前缀总数:{len(dat_prefixes)} 个") # 4. 第一次匹配:完整前缀匹配 first_copied = [] # [(dat前缀, OBJ文件名)] for prefix in dat_prefixes: lower_prefix = prefix.lower() if lower_prefix in obj_lower_to_info: obj_original, obj_path = obj_lower_to_info[lower_prefix] obj_filename = os.path.basename(obj_path) dest_path = os.path.join(dest_dir, obj_filename) if not os.path.exists(dest_path): shutil.copy2(obj_path, dest_path) first_copied.append((prefix, obj_filename)) print(f"\n第一次匹配完成:{len(first_copied)} 个前缀匹配成功") # 5. 第二次匹配:未匹配前缀提取前导数字 matched_prefixes = {p for p, _ in first_copied} not_found_first = [p for p in dat_prefixes if p not in matched_prefixes] print(f"初始未匹配的前缀:{len(not_found_first)} 个") second_copied = [] # [(dat前缀, OBJ文件名, 提取的数字)] if not_found_first: for prefix in not_found_first: leading_digits = extract_leading_digits(prefix) if not leading_digits: continue target_lower = leading_digits.lower() if target_lower in obj_lower_to_info: obj_original, obj_path = obj_lower_to_info[target_lower] obj_filename = os.path.basename(obj_path) dest_path = os.path.join(dest_dir, obj_filename) if not os.path.exists(dest_path): shutil.copy2(obj_path, dest_path) second_copied.append((prefix, obj_filename, leading_digits)) print(f"第二次匹配完成:{len(second_copied)} 个前缀匹配成功") # 6. 最终结果汇总 print("\n" + "=" * 60) print("最终结果汇总") print("=" * 60) total_matched = len(first_copied) + len(second_copied) print(f"📊 统计信息:") print(f" - JSON中.dat键名总数:{len(json_keys)}") print(f" - 第一次匹配成功:{len(first_copied)}") print(f" - 第二次匹配成功:{len(second_copied)}") print(f" - 总匹配成功:{total_matched}") print(f" - 最终未匹配:{len(dat_prefixes) - total_matched}") print(f"\n🏁 所有操作完成!复制的文件保存至:{dest_dir}") except Exception as e: print(f"❌ 复制操作失败: {str(e)}") def main(): # 配置文件路径 JSON_FILE_PATH = "/public/home/wangshuo/gap/assembly/data/car_1k/subset_self/label_mapping_freq.json" OBJ_SOURCE_DIR = "/public/home/wangshuo/gap/assembly/data/part_obj" DEST_DIR = "/public/home/wangshuo/gap/assembly/data/part_obj_300" # 执行完整流程 print("=" * 80) print("JSON键名分析与OBJ文件复制工具") print("=" * 80) # 第一步:分析JSON键名与前缀的关系 json_keys, _ = compare_json_and_prefixes(JSON_FILE_PATH) if not json_keys: print("❌ 未获取到有效的JSON键名,无法继续操作") return # 第二步:基于分析结果进行OBJ文件复制 copy_obj_files(JSON_FILE_PATH, OBJ_SOURCE_DIR, DEST_DIR, json_keys) if __name__ == "__main__": main()