You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从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}")

代码说明

  1. 数据属性统一:将existing_timetable_data改为self.timetable_data,确保所有加载方法都往同一个属性写入数据,避免找不到数据的问题。
  2. JSON数据处理优化:遍历JSON中的每个列车,将列车名称作为新列Train Name,同时把每个站点拆分为单独行,确保每条记录对应一个站点+列车的组合,符合CSV的结构化存储要求。
  3. 必填行适配:针对新增的Train Name列,调整必填行的填充逻辑,确保每个列车名称都能正确对应到表头位置。
  4. 错误判断简化:简化create_timetable_file中的数据和路径判断逻辑,避免重复抛出相同错误,提高代码可读性。

内容的提问来源于stack exchange,提问作者DEV DD

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 09:45:54