CS50 Python Week3作业Outdated:区分输入格式与数值范围错误处理
CS50 Python Outdated作业问题修复方案
问题描述
做CS50 Python第三周的Outdated作业时碰到的问题:
- 作业要求:写个程序接收两种格式的日期——
MM/DD/YYYY或者英文月份格式(比如September 8, 1636),转成YYYY-MM-DD格式输出;如果输入无效,就得重新提示用户输入。 - 当前代码的问题:
- 输入完全不符合格式要求时(比如数字格式日期里混了非数字内容)直接报错崩溃,没法正常拒绝并重新提示
- 日期、月份数值超出范围时的重新提示逻辑混乱,递归调用导致流程出错
原代码核心问题
- 没做异常处理:处理数字格式日期时,直接用
int()转分割后的字符串,碰到非数字就会抛出ValueError程序崩了 - 格式校验太松:
- 数字格式没检查是不是刚好分成3部分(比如输入
1/2020会直接索引越界) - 英文格式没检查分割后的部分数量,也没校验日期后面的逗号是否存在
- 数字格式没检查是不是刚好分成3部分(比如输入
- 错误处理逻辑乱:用递归调用
check()来重新获取输入,导致函数栈嵌套,原来的循环逻辑完全失效 - 日期合法性校验不全:只检查了日期是否大于31,没考虑不同月份的天数差异(比如2月最多28/29天,4月最多30天)
修复后的代码
MONTHS = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ] def is_leap_year(year): # 判断闰年,用来校验2月的天数 if year % 4 != 0: return False elif year % 100 != 0: return True else: return year % 400 == 0 def get_max_days(month, year): # 返回对应月份的最大天数 if month in [4, 6, 9, 11]: return 30 elif month == 2: return 29 if is_leap_year(year) else 28 else: return 31 def validate_numeric_date(date_str): # 校验并解析数字格式的日期 parts = date_str.split("/") if len(parts) != 3: return None try: month = int(parts[0]) day = int(parts[1]) year = int(parts[2]) except ValueError: return None # 校验月份范围 if not (1 <= month <= 12): return None # 校验日期范围 max_day = get_max_days(month, year) if not (1 <= day <= max_day): return None return (year, month, day) def validate_word_date(date_str): # 校验并解析英文月份格式的日期 parts = date_str.split() if len(parts) != 3: return None month_name, day_part, year_str = parts # 校验月份名称 month_name = month_name.title() if month_name not in MONTHS: return None month = MONTHS.index(month_name) + 1 # 处理日期部分的逗号 if not day_part.endswith(","): return None day_str = day_part[:-1] try: day = int(day_str) year = int(year_str) except ValueError: return None # 校验日期范围 max_day = get_max_days(month, year) if not (1 <= day <= max_day): return None return (year, month, day) def main(): while True: date_input = input("Date: ").strip() # 先尝试解析数字格式 result = validate_numeric_date(date_input) if result: year, month, day = result print(f"{year}-{month:02d}-{day:02d}") break # 再尝试解析英文格式 result = validate_word_date(date_input) if result: year, month, day = result print(f"{year}-{month:02d}-{day:02d}") break # 格式无效,重新提示输入 continue if __name__ == "__main__": main()
关键改进点
- 统一输入循环逻辑:用
main()里的while True循环处理输入,代替原来的递归调用,流程清晰可控 - 完善异常处理:解析数字时用
try-except捕获ValueError,避免程序崩溃 - 严格格式校验:
- 数字格式检查是否刚好分割为3部分
- 英文格式检查分割为3部分、日期部分是否带逗号
- 完整日期合法性校验:
- 添加闰年判断,准确校验2月的天数
- 区分不同月份的最大天数(30/31天)
- 模块化拆分:把日期校验、闰年判断、最大天数计算拆成独立函数,代码更易维护
- 返回值清晰:校验函数返回
None表示输入无效,返回合法的(year, month, day)元组表示有效,逻辑明确
内容的提问来源于stack exchange,提问作者Koh Cw
相关产品推荐
相关产品推荐

