从JSON生成CSV游戏时刻表遇ValueError,求代码修正方案
代码修正方案:解决ValueError并添加列车名称列
核心问题分析与修复
1. 解决ValueError: Data must be provided
- 原代码中
load_timetable_data方法加载CSV时赋值给self.existing_timetable_data,但文件不存在时却设置self.timetable_data = None,属性名不统一,导致后续create_timetable_file无法正确读取数据。 - 统一数据存储属性为
self.timetable_data,确保加载逻辑一致。 - 优化
create_timetable_file中的数据判断逻辑,避免重复抛出错误。
2. 添加列车名称列
- 原JSON结构中,键名是列车名称,值是该列车的时刻表数据。需要遍历每个列车,将列车名称作为单独列添加到DataFrame中,同时将站点拆分为单独行,匹配对应列车的时刻信息。
修正后的完整代码
import pandas as pd import json class Read_Create_TimeTable_File: def __init__(self, file_path=None): self.file_path = file_path self.timetable_data = None # 统一使用该属性存储数据 if file_path is not None: self.load_timetable_data(file_path) def set_file_path(self, file_path): if not file_path.endswith(".timetable_or"): file_path += ".timetable_or" self.file_path = file_path self.load_timetable_data(file_path) def load_timetable_data(self, file_path): try: self.timetable_data = pd.read_csv(file_path, sep=";", encoding="utf-16le") except FileNotFoundError: self.timetable_data = None def load_timetable_data_from_json(self, json_file_path): try: with open(json_file_path, "r") as f: data_dict = json.load(f) # 处理多列车数据,提取列车名称并构建结构化DataFrame rows = [] for train_name, train_data in data_dict.items(): # 提取列车的全局属性 start_time = train_data.get("#start", "") speed_kph = train_data.get("#speedkph", "") dispose = train_data.get("#dispose", "") # 遍历站点数据 for station, time_info in train_data.items(): # 跳过全局属性行,只处理站点 if station.startswith("#"): continue rows.append({ "Train Name": train_name, "#start": start_time, "#speedkph": speed_kph, "#dispose": dispose, "Station": station, "Time": time_info }) self.timetable_data = pd.DataFrame(rows) except FileNotFoundError: self.timetable_data = None def create_timetable_file(self, file_path=None, data=None): # 优先使用传入的data,其次用实例的timetable_data data = data or self.timetable_data if data is None: raise ValueError("Data must be provided.") # 处理文件路径 self.file_path = file_path or self.file_path if self.file_path is None: raise ValueError("File path must be provided.") if not self.file_path.endswith(".timetable_or"): self.file_path += ".timetable_or" # 调整列顺序,确保列车名称列在前面 if "Train Name" in data.columns: # 重新排列列:空列、#comment、Train Name、Station、其他列 cols = ["", "#comment", "Train Name", "Station", "#start", "#speedkph", "#dispose", "Time"] # 确保所有列都被包含 cols += [col for col in data.columns if col not in cols] data = data[cols] else: # 兼容原有数据结构 data.insert(0, '#comment', '') data.insert(0, '', '') # 构建必填行 mandatory_rows = [ ["#comment", "", "", ""] + [""] * (len(data.columns) - 4), ["#path /binary", "", "", ""] + [""] * (len(data.columns) - 4), ["#consist", "", "", ""] + [""] * (len(data.columns) - 4), ["#start", "", "", ""] + [""] * (len(data.columns) - 4), ["#speedkph", "", "", ""] + [""] * (len(data.columns) - 4), ["#comment", "", "", ""] + [""] * (len(data.columns) - 4), ["#note", "", "", ""] + [""] * (len(data.columns) - 4), ["#dispose", "", "", ""] + [""] * (len(data.columns) - 4), [""] * len(data.columns), ] mandatory_rows_df = pd.DataFrame(mandatory_rows, columns=data.columns) # 填充必填行的列车名称列(如果存在) if "Train Name" in data.columns: # 获取所有唯一的列车名称 train_names = data["Train Name"].unique() for col_idx, train_name in enumerate(train_names, start=3): # 第4列是Train Name(索引3) if col_idx >= len(mandatory_rows_df.columns): break for row in ["#comment", "#path /binary", "#consist"]: row_index = mandatory_rows_df[mandatory_rows_df["Station"] == row].index[0] mandatory_rows_df.loc[row_index, mandatory_rows_df.columns[col_idx]] = train_name else: # 原有逻辑处理 for col in data.columns[3:]: for row in ["#comment", "#path /binary", "#consist"]: row_index = mandatory_rows_df[mandatory_rows_df["Station"] == row].index[0] mandatory_rows_df.loc[row_index, col] = col # 填充第一个#comment行的文件名 first_comment_index = mandatory_rows_df[mandatory_rows_df["Station"] == "#comment"].index[0] mandatory_rows_df.loc[first_comment_index, "#comment"] = self.file_path.replace(".timetable_or", "") # 合并最终数据 final_data = pd.concat([mandatory_rows_df, data], ignore_index=True) # 保存文件 final_data.to_csv(self.file_path, sep=";", index=False, encoding="utf-16le") print(f"Timetable file created at {self.file_path}")
代码说明
- 数据属性统一:将
existing_timetable_data改为self.timetable_data,确保所有加载方法都往同一个属性写入数据,避免找不到数据的问题。 - JSON数据处理优化:遍历JSON中的每个列车,将列车名称作为新列
Train Name,同时把每个站点拆分为单独行,确保每条记录对应一个站点+列车的组合,符合CSV的结构化存储要求。 - 必填行适配:针对新增的
Train Name列,调整必填行的填充逻辑,确保每个列车名称都能正确对应到表头位置。 - 错误判断简化:简化
create_timetable_file中的数据和路径判断逻辑,避免重复抛出相同错误,提高代码可读性。
内容的提问来源于stack exchange,提问作者DEV DD
相关产品推荐
相关产品推荐

