Created
April 17, 2025 09:20
-
-
Save townie/47a7cf4a1a70bb0852284d5a7f27d6cb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def ordinal_to_roman(ordinal): | |
""" | |
Converts a chapter ordinal (number, word, or Roman numeral) to a Roman numeral. | |
Args: | |
ordinal: The chapter ordinal, which can be an integer, a word | |
representation of a number (e.g., "one", "two"), or a | |
Roman numeral string. | |
Returns: | |
The Roman numeral representation of the ordinal, or None if the | |
input cannot be converted. | |
Examples: | |
ordinal_to_roman(1) == "I" | |
ordinal_to_roman("2") == "II" | |
ordinal_to_roman("three") == "III" | |
ordinal_to_roman("IV") == "IV" | |
ordinal_to_roman(5) == "V" | |
ordinal_to_roman(10) == "X" | |
ordinal_to_roman(15) == "XV" | |
ordinal_to_roman(20) == "XX" | |
ordinal_to_roman(50) == "L" | |
ordinal_to_roman(100) == "C" | |
ordinal_to_roman(500) == "D" | |
ordinal_to_roman(1000) == "M" | |
ordinal_to_roman("one") == "I" | |
ordinal_to_roman("two") == "II" | |
ordinal_to_roman("three") == "III" | |
ordinal_to_roman("four") == "IV" | |
ordinal_to_roman("five") == "V" | |
ordinal_to_roman("six") == "VI" | |
ordinal_to_roman("seven") == "VII" | |
ordinal_to_roman("eight") == "VIII" | |
ordinal_to_roman("nine") == "IX" | |
ordinal_to_roman("ten") == "X" | |
ordinal_to_roman(11) == "XI" | |
ordinal_to_roman(12) == "XII" | |
ordinal_to_roman(13) == "XIII" | |
ordinal_to_roman(14) == "XIV" | |
ordinal_to_roman(15) == "XV" | |
ordinal_to_roman(16) == "XVI" | |
ordinal_to_roman(17) == "XVII" | |
ordinal_to_roman(18) == "XVIII" | |
ordinal_to_roman(19) == "XIX" | |
ordinal_to_roman(20) == "XX" | |
ordinal_to_roman(21) == "XXI" | |
ordinal_to_roman(24) == "XXIV" | |
ordinal_to_roman(25) == "XXV" | |
ordinal_to_roman(26) == "XXVI" | |
ordinal_to_roman(27) == "XXVII" | |
ordinal_to_roman(28) == "XXVIII" | |
ordinal_to_roman(29) == "XXIX" | |
ordinal_to_roman(30) == "XXX" | |
ordinal_to_roman(40) == "XL" | |
ordinal_to_roman(49) == "XLIX" | |
ordinal_to_roman(50) == "L" | |
ordinal_to_roman(90) == "XC" | |
ordinal_to_roman(99) == "XCIX" | |
ordinal_to_roman(100) == "C" | |
ordinal_to_roman(400) == "CD" | |
ordinal_to_roman(500) == "D" | |
ordinal_to_roman(900) == "CM" | |
ordinal_to_roman(1000) == "M" | |
ordinal_to_roman(1994) == 'MCMXCIV' | |
ordinal_to_roman(3999) == 'MMMCMXCIX' | |
""" | |
if not ordinal: | |
return None | |
# Define the Roman numeral values | |
roman_map = { | |
1: "I", | |
4: "IV", | |
5: "V", | |
9: "IX", | |
10: "X", | |
40: "XL", | |
50: "L", | |
90: "XC", | |
100: "C", | |
400: "CD", | |
500: "D", | |
900: "CM", | |
1000: "M", | |
} | |
# Handle integer input | |
if isinstance(ordinal, (int, float)): | |
try: | |
num = int(ordinal) # Convert float to int if necessary | |
except ValueError: | |
return None # Handle invalid numeric input | |
if num <= 0 or num > 3999: | |
return None # Roman numerals are not defined for these numbers | |
# Handle string input (word or Roman numeral) | |
elif isinstance(ordinal, str): | |
ordinal = ordinal.strip().lower() # remove white spaces and convert to lower | |
# Try converting word to number | |
word_to_num = { | |
"one": 1, | |
"two": 2, | |
"three": 3, | |
"four": 4, | |
"five": 5, | |
"six": 6, | |
"seven": 7, | |
"eight": 8, | |
"nine": 9, | |
"ten": 10, | |
"eleven": 11, | |
"twelve": 12, | |
"thirteen": 13, | |
"fourteen": 14, | |
"fifteen": 15, | |
"sixteen": 16, | |
"seventeen": 17, | |
"eighteen": 18, | |
"nineteen": 19, | |
"twenty": 20, | |
"thirty": 30, | |
"forty": 40, | |
"fifty": 50, | |
"sixty": 60, | |
"seventy": 70, | |
"eighty": 80, | |
"ninety": 90, | |
"hundred": 100, | |
"thousand": 1000, | |
} | |
if ordinal in word_to_num: | |
num = word_to_num[ordinal] | |
else: | |
# Attempt to convert from Roman numeral string to integer | |
roman_numeral_map = { | |
"I": 1, | |
"V": 5, | |
"X": 10, | |
"L": 50, | |
"C": 100, | |
"D": 500, | |
"M": 1000, | |
} | |
i = 0 | |
number = 0 | |
while i < len(ordinal): | |
char = ordinal[i] | |
if char not in roman_numeral_map: | |
return None | |
val = roman_numeral_map[char] | |
if i + 1 < len(ordinal): | |
next_char = ordinal[i + 1] | |
next_val = roman_numeral_map[next_char] | |
if val < next_val: | |
number += next_val - val | |
i += 2 | |
else: | |
number += val | |
i += 1 | |
else: | |
number += val | |
i += 1 | |
num = number | |
else: | |
return None | |
if num <= 0 or num > 3999: | |
return None # Roman numerals are not defined for these numbers | |
# Convert the number to a Roman numeral | |
result = "" | |
values = sorted(roman_map.keys(), reverse=True) | |
for value in values: | |
while num >= value: | |
result += roman_map[value] | |
num -= value | |
return result |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment