From 1559ff2411d04975e95f00aa6a6bef033e75f9c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=B0=E8=A8=80?= Date: Mon, 29 Jun 2026 13:09:01 +0800 Subject: [PATCH] feat(conversions): add input validation and fix bugs in Roman Numerals and Excel Column Title conversions --- conversions/excel_title_to_column.py | 19 +++++++++++++- conversions/roman_numerals.py | 38 +++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/conversions/excel_title_to_column.py b/conversions/excel_title_to_column.py index d77031ec26f2..54e1a16d2972 100644 --- a/conversions/excel_title_to_column.py +++ b/conversions/excel_title_to_column.py @@ -12,8 +12,25 @@ def excel_title_to_column(column_title: str) -> int: 28 >>> excel_title_to_column("Z") 26 + >>> excel_title_to_column("a") + 1 + >>> excel_title_to_column("ab") + 28 + >>> excel_title_to_column("") + Traceback (most recent call last): + ... + ValueError: Column title must be a non-empty string containing only alphabetic characters. + >>> excel_title_to_column("A1") + Traceback (most recent call last): + ... + ValueError: Column title must be a non-empty string containing only alphabetic characters. """ - assert column_title.isupper() + if not column_title or not column_title.isalpha(): + raise ValueError( + "Column title must be a non-empty string containing only alphabetic characters." + ) + + column_title = column_title.upper() answer = 0 index = len(column_title) - 1 power = 0 diff --git a/conversions/roman_numerals.py b/conversions/roman_numerals.py index 75af2ac72882..fe35759ea7f8 100644 --- a/conversions/roman_numerals.py +++ b/conversions/roman_numerals.py @@ -24,8 +24,25 @@ def roman_to_int(roman: str) -> int: >>> tests = {"III": 3, "CLIV": 154, "MIX": 1009, "MMD": 2500, "MMMCMXCIX": 3999} >>> all(roman_to_int(key) == value for key, value in tests.items()) True + >>> roman_to_int("iii") + 3 + >>> roman_to_int("") + Traceback (most recent call last): + ... + ValueError: Input cannot be an empty string + >>> roman_to_int("MIX-abc") + Traceback (most recent call last): + ... + ValueError: Invalid Roman numeral character: - """ vals = {"I": 1, "V": 5, "X": 10, "L": 50, "C": 100, "D": 500, "M": 1000} + roman = roman.upper() + if not roman: + raise ValueError("Input cannot be an empty string") + for char in roman: + if char not in vals: + raise ValueError(f"Invalid Roman numeral character: {char}") + total = 0 place = 0 while place < len(roman): @@ -40,12 +57,31 @@ def roman_to_int(roman: str) -> int: def int_to_roman(number: int) -> str: """ - Given a integer, convert it to an roman numeral. + Given an integer, convert it to a roman numeral. https://en.wikipedia.org/wiki/Roman_numerals >>> tests = {"III": 3, "CLIV": 154, "MIX": 1009, "MMD": 2500, "MMMCMXCIX": 3999} >>> all(int_to_roman(value) == key for key, value in tests.items()) True + >>> int_to_roman(0) + Traceback (most recent call last): + ... + ValueError: Input must be an integer between 1 and 3999 + >>> int_to_roman(-5) + Traceback (most recent call last): + ... + ValueError: Input must be an integer between 1 and 3999 + >>> int_to_roman(4000) + Traceback (most recent call last): + ... + ValueError: Input must be an integer between 1 and 3999 + >>> int_to_roman(1.5) # type: ignore[arg-type] + Traceback (most recent call last): + ... + ValueError: Input must be an integer between 1 and 3999 """ + if not isinstance(number, int) or not (0 < number < 4000): + raise ValueError("Input must be an integer between 1 and 3999") + result = [] for arabic, roman in ROMAN: (factor, number) = divmod(number, arabic)