Skip to content

Instantly share code, notes, and snippets.

@yrps
Created November 23, 2015 07:05
Show Gist options
  • Select an option

  • Save yrps/6efa6ec4cc8950be8f4a to your computer and use it in GitHub Desktop.

Select an option

Save yrps/6efa6ec4cc8950be8f4a to your computer and use it in GitHub Desktop.
Regexp-based conversion from Roman numerals to decimal
#!/bin/python3
__author__ = 'ncoop'
from re import search, VERBOSE, IGNORECASE
roman_pattern = '''
^
# M: thousands
((?P<m1000>M)|(?P<m2000>MM)|(?P<m3000>MMM))?
# C,D: hundreds
((?P<c100>C)|(?P<c200>CC)|(?P<c300>CCC)|(?P<c400>CD)|(?P<c500>D)|
(?P<c600>DC)|(?P<c700>DCC)|(?P<c800>DCCC)|(?P<c900>CM))?
# X,L: tens
((?P<x10>X)|(?P<x20>XX)|(?P<x30>XXX)|(?P<x40>XL)|(?P<x50>L)|
(?P<x60>LX)|(?P<x70>LXX)|(?P<x80>LXXX)|(?P<x90>XC))?
# I,V: ones
((?P<i1>I)|(?P<i2>II)|(?P<i3>III)|(?P<i4>IV)|(?P<i5>V)|
(?P<i6>VI)|(?P<i7>VII)|(?P<i8>VIII)|(?P<i9>IX))?
$
'''
def rom2dec(roman_string, ignore_case=False) -> int:
"""
Convert a string of Roman numerals to its int equivalent.
Minimum 0 for empty string, maximum 3999 for MMMCMXCIX
Returns None for invalid string.
:rtype : int
:param roman_string: the string to be converted
:param ignore_case: True if case-insensitivity is required
:return: the int value of the string
"""
match = search(roman_pattern, roman_string, VERBOSE | (IGNORECASE if ignore_case else 0))
if not match:
return None
match_dict = match.groupdict()
# filter out unmatched groups, interpret the key as an int value, and sum the results
return sum([int(k[1:]) for k in match_dict if match_dict[k]])
if __name__ == '__main__':
for r in ['', 'I', 'iv', 'VIII', 'XXI', 'LXXX', 'XC', 'MMM', 'MMI', 'MMCMIII', 'mmmCMXCIX']:
print(r + ' => ' + str(rom2dec(r, True)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment