Skip to content

Instantly share code, notes, and snippets.

@khardix
Last active August 29, 2015 14:28
Show Gist options
  • Save khardix/44d4b16f5fb1d1291a81 to your computer and use it in GitHub Desktop.
Save khardix/44d4b16f5fb1d1291a81 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
ROMAN_NUMBERS = {
1000: 'M', 900: 'CM', 500: 'D', 400: 'CD',
100: 'C', 90: 'XC', 50: 'L', 40: 'XL',
10: 'X', 9: 'IX', 5: 'V', 4: 'IV',
1: 'I'
}
def to_roman(value):
"""Convert integer value to roman numeral string.
Keyword arguments:
value -- Converted value.
Returns: string
"""
value = int(value)
if value <= 0:
raise ValueError("Value too small (<= 0)")
steps = sorted(ROMAN_NUMBERS.keys())
output = ""
while value > 0:
step = steps[-1]
if step <= value: # Substract and convert
value -= step
output += ROMAN_NUMBERS[step]
else: # Move to lesser one
steps.pop()
return output
def from_roman(value):
"""Convert string of roman numerals to number.
Keyword arguments:
value -- String representing roman numeral.
Returns: integer, or None if the input is empty string
"""
# Backward conversion
SYMBOLS = {symbol: value for value, symbol in ROMAN_NUMBERS.items()}
SYM_MAX = max([len(symbol) for symbol in SYMBOLS.keys()])
output = 0
remains = value.strip()
while len(remains) > 0:
if remains.startswith(tuple(SYMBOLS.keys())):
for l in range(SYM_MAX, 0, -1): # find the prefix, start from longest
if remains[:l] in SYMBOLS:
output += SYMBOLS[remains[:l]]
remains = remains[l:]
break
else:
raise ValueError("Invalid roman numeral")
if output == 0:
return None
else:
return output
if __name__ == '__main__':
from sys import stdin
from argparse import ArgumentParser, SUPPRESS
def words(istream=stdin):
"""Yields words from input stream."""
for line in istream:
for word in line.split(): yield word
parser = ArgumentParser(description="Converts numbers to/from roman numerals.")
conversions = parser.add_mutually_exclusive_group(required=False)
conversions.add_argument('-t', '--to-roman', dest="number", nargs='*', type=int, default=SUPPRESS,
help="Convert integer to roman number"
)
conversions.add_argument('-f', '--from-roman', dest="roman", nargs='*', type=str, default=SUPPRESS,
help="Convert roman literal to integer"
)
arguments = vars(parser.parse_args())
# Source - an iterable which produces words to be converted
# Converter - actual converting function
if "number" in arguments: # To roman
(source, converter) = (arguments["number"], to_roman)
elif "roman" in arguments: # To integer
(source, converter) = (arguments["roman"], from_roman)
else: # Default - try to roman
(source, converter) = (None, to_roman)
# Detect "empty" input and switch to stdin
if source is None or len(source) == 0: source = words(stdin)
try:
for value in source: print(converter(value))
except ValueError as err:
raise SystemExit("Error: " + str(err))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment