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

正则匹配时间格式失败引发AttributeError而非ValueError的原因

问题分析:输入无空格时间字符串触发AttributeError的原因及修复

问题描述

我希望convert函数能验证格式为“9 AM to 5 PM”或“9:00 AM to 5:00 PM”的字符串,当时间与AM/PM之间无空格(例如“9AM to 5PM”)或格式错误时,抛出ValueError。但实际输入“9AM to 5PM”时,却触发了AttributeError,提示'NoneType'对象没有'group'属性,请问这是为什么?

现有代码如下:

import re
import sys

def main():
    try:
        print(convert(input("Hours: ")))
    except ValueError:
        print("Invalid format. Please use '9:00 AM to 5:00 PM' or '9 AM to 5 PM'.")

def convert(s):
    matches = re.search(r"^([0-9]+):?([0-9]+)? (AM|PM) to ([0-9]+):?([0-9]+)? (AM|PM)$", s)

    hour1 = int(matches.group(1))
    minute1 = int(matches.group(2) or 0)
    hour2 = int(matches.group(4))
    minute2 = int(matches.group(5) or 0)
    am_pm1 = matches.group(3).upper()
    am_pm2 = matches.group(6).upper()

    if matches:
        if hour1 > 12 or hour2 > 12 or minute1 > 59 or minute2 > 59:
            raise ValueError
        if hour1 == 12 and am_pm1 == "AM":
            hour1 = 0
        elif hour1 != 12 and am_pm1 == "PM":
            hour1 += 12
        if hour2 == 12 and am_pm2 == "AM":
            hour2 = 0
        elif hour2 != 12 and am_pm2 == "PM":
            hour2 += 12
    else:
        raise ValueError

    time1 = f"{hour1:02}:{minute1:02}"
    time2 = f"{hour2:02}:{minute2:02}"
    
    return time1 + " to " + time2

if __name__ == "__main__":
    main()

错误原因

核心问题是正则匹配失败后直接调用了matches.group()方法:

  • 当输入“9AM to 5PM”时,你的正则表达式要求时间数字与AM/PM之间必须有空格,但输入中没有这个空格,导致re.search()无法匹配,返回None。
  • 代码中先执行了matches.group(1)等分组提取操作,之后才检查matches是否有效。此时matches是None,调用group()方法自然会触发AttributeError,而不是预期的ValueError。

修复方案

调整代码执行顺序,先验证正则匹配结果,再提取分组内容:

  1. 在调用任何matches.group()之前,先判断matches是否不为None,如果匹配失败直接抛出ValueError。
  2. 移除原代码中冗余的else分支,提前的判断已经覆盖了匹配失败的场景。

修正后的完整代码

import re
import sys

def main():
    try:
        print(convert(input("Hours: ")))
    except ValueError:
        print("Invalid format. Please use '9:00 AM to 5:00 PM' or '9 AM to 5 PM'.")

def convert(s):
    matches = re.search(r"^([0-9]+):?([0-9]+)? (AM|PM) to ([0-9]+):?([0-9]+)? (AM|PM)$", s)

    # 先检查匹配结果,失败直接抛出ValueError
    if not matches:
        raise ValueError

    # 匹配成功后再提取分组内容
    hour1 = int(matches.group(1))
    minute1 = int(matches.group(2) or 0)
    hour2 = int(matches.group(4))
    minute2 = int(matches.group(5) or 0)
    am_pm1 = matches.group(3).upper()
    am_pm2 = matches.group(6).upper()

    # 验证时间数值的合法性
    if hour1 > 12 or hour2 > 12 or minute1 > 59 or minute2 > 59:
        raise ValueError
    if hour1 == 12 and am_pm1 == "AM":
        hour1 = 0
    elif hour1 != 12 and am_pm1 == "PM":
        hour1 += 12
    if hour2 == 12 and am_pm2 == "AM":
        hour2 = 0
    elif hour2 != 12 and am_pm2 == "PM":
        hour2 += 12

    time1 = f"{hour1:02}:{minute1:02}"
    time2 = f"{hour2:02}:{minute2:02}"
    
    return time1 + " to " + time2

if __name__ == "__main__":
    main()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 05:43:16