Exercise 1 solution import re time_re = re.compile(r"(\d{2}):(\d{2})") def valid_time(s): m = time_re.fullmatch(s) return bool(m) and int(m[1]) <= 23 and int(m[2]) <= 59 for s in ["09:30", "23:59", "24:00", "12:60", "9:30"]: print(s, valid_time(s)) # 09:30 True # 23:59 True # 24:00 False # 12:60 False # 9:30 False (All lines were run and printed exactly what is shown.) Explanation: the pattern checks the shape (two digits, a colon, two digits) and fullmatch makes it cover the whole string. The ranges are then checked with ordinary comparisons, which is far simpler than encoding 00-23 and 00-59 in the pattern. "bool(m) and ..." stops early when there is no match, so m[1] is never used on None.