Skip to content

Instantly share code, notes, and snippets.

@townie
Created April 17, 2025 09:20
Show Gist options
  • Save townie/47a7cf4a1a70bb0852284d5a7f27d6cb to your computer and use it in GitHub Desktop.
Save townie/47a7cf4a1a70bb0852284d5a7f27d6cb to your computer and use it in GitHub Desktop.
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