CS50 Scourgify问题:程序输出符合预期却测试失败求助
CS50 Scourgify问题排查
问题描述
我正在解决CS50的scourgify问题,before.csv文件包含name和house两列,任务是将name列拆分为first和last独立列,然后生成包含first、last、house的新CSV文件。程序输出看起来符合预期,但测试时收到错误提示::( scourgify.py cleans short CSV file,原因是scourgify.py未生成指定格式的CSV,长CSV文件测试也无法进行。
我的代码实现
import sys import csv def main(): if len(sys.argv) >= 4: print("Too many command-line arguments") sys.exit(1) if len(sys.argv) <= 2: print("Too few command-line arguments") sys.exit(1) filepath1 = sys.argv[1] filepath2 = sys.argv[2] if not filepath1.endswith(".csv") or not filepath2.endswith(".csv"): print("Not a CSV file") sys.exit(1) data = read_from_file(filepath1) writer = write_to_file(filepath2, data) def read_from_file(filepath): updated_data = [] try: with open(filepath, "r") as file: data = csv.DictReader(file) for i in data: name = i["name"] house = i["house"] first, last = name.split(", ") new_dict = { "first": first, "last": last, "house": house, } updated_data.append(new_dict) except FileNotFoundError: print("File does not exist") sys.exit(1) return updated_data def write_to_file(filepath, new_data): fieldnames = ["first", "last", "house"] try: with open(filepath, mode="w") as file: writer = csv.DictWriter(file, fieldnames=fieldnames) writer.writeheader() writer.writerows(new_data) except FileNotFoundError: print("File does not exist") sys.exit(1) if __name__ == "__main__": main()
问题分析与解决
核心问题
测试失败的关键原因是姓名拆分逻辑不够稳健:
你使用name.split(", ")拆分姓名,但如果测试用例中存在没有逗号分隔的姓名(比如短CSV里的单个名字),或者姓名格式不符合Last, First的情况,split后得到的元素数量不足2个,会直接触发ValueError,导致程序提前退出,无法生成完整的输出文件,因此测试判定“未生成指定格式的CSV”。
另外,写入CSV时未指定newline=''参数,在Windows环境下可能会生成多余的空行,也可能影响测试结果。
修复方案
- 优化姓名拆分逻辑:使用
split(", ", 1)限制最多拆分一次,同时处理拆分后元素不足的情况,避免触发异常。 - 添加异常捕获:处理CSV列名缺失、格式错误等潜在问题,避免程序意外崩溃。
- 优化命令行参数检查:简化判断逻辑,给出更清晰的使用提示。
- 修正CSV写入参数:添加
newline=''避免多余空行。
修改后的代码
import sys import csv def main(): # 简化命令行参数检查 if len(sys.argv) != 3: print("Usage: python scourgify.py input.csv output.csv") sys.exit(1) input_path = sys.argv[1] output_path = sys.argv[2] if not input_path.endswith(".csv") or not output_path.endswith(".csv"): print("Not a CSV file") sys.exit(1) data = read_from_file(input_path) write_to_file(output_path, data) def read_from_file(filepath): updated_data = [] try: with open(filepath, "r") as file: reader = csv.DictReader(file) # 检查必要列是否存在 required_columns = {"name", "house"} if not required_columns.issubset(reader.fieldnames): missing = required_columns - set(reader.fieldnames) print(f"Missing required columns: {', '.join(missing)}") sys.exit(1) for row in reader: name = row["name"].strip() house = row["house"].strip() # 稳健拆分姓名,最多拆分一次 name_parts = name.split(", ", 1) if len(name_parts) == 2: last_name, first_name = name_parts first_name = first_name.strip() else: # 处理无逗号的情况,默认将全名设为last_name last_name = name_parts[0].strip() first_name = "" updated_data.append({ "first": first_name, "last": last_name, "house": house }) except FileNotFoundError: print("File does not exist") sys.exit(1) return updated_data def write_to_file(filepath, new_data): fieldnames = ["first", "last", "house"] try: # 添加newline=''避免Windows下多余空行 with open(filepath, mode="w", newline='') as file: writer = csv.DictWriter(file, fieldnames=fieldnames) writer.writeheader() writer.writerows(new_data) except Exception as e: print(f"Error writing file: {e}") sys.exit(1) if __name__ == "__main__": main()
关键修改点说明
- 用
len(sys.argv) !=3替代原来的两次判断,直接提示正确的命令格式。 - 检查CSV是否包含
name和house列,提前报错避免后续KeyError。 - 使用
split(", ",1)限制拆分次数,确保即使姓名中包含多个逗号也只会拆分一次。 - 处理无逗号的姓名情况,避免触发ValueError。
- 写入CSV时添加
newline='',符合csv模块的官方推荐用法,避免跨平台换行问题。
内容的提问来源于stack exchange,提问作者Sunnat Amirov
相关产品推荐
相关产品推荐

