整数・ローマ数字変換(Python版)
http://d.hatena.ne.jp/fumokmm/20110822/1314013182
アラビア数字 <=> ローマ数字変換を行う関数、arabicToRoman および romanToArabic を実装せよ。
条件)
・ローマ数字の表記法についてはローマ数字 - Wikipediaを参考にすること。
・ローマ数字は半角英「I,V,X,L,C,D,M,i,v,x,l,c,d,m」のみ使用した文字列とし、それ以外はエラーとする。
・アラビア数字は整数 1 から 3999 のみ使用するものとし、それ以外はエラーとする。変換例)
11 <=> XI
12 <=> XII
14 <=> XIV
18 <=> XVIII
24 <=> XXIV
43 <=> XLIII
99 <=> XCIX
495 <=> CDXCV
1888 <=> MDCCCLXXXVIII
1945 <=> MCMXLV
3999 <=> MMMCMXCIXコードサンプル)
arabicToRoman(11) => "XI"
romanToArabic("MDCCCLXXXVIII") => 1888
romanToArabic("mdccclxxxviii") => 1888
romanToArabic("McmXLv") => 1945
arabicToRoman(0) => エラー
romanToArabic("A") => エラー
Pythonで解いてみました。関数名は変えてあります。
#!python3 #encoding:shift-jis import re DIGIT_STRINGS = { 1: dict(enumerate("I II III IV V VI VII VIII IX".split(), 1)), 2: dict(enumerate("X XX XXX XL L LX LXX LXXX XC".split(), 1)), 3: dict(enumerate("C CC CCC CD D DC DCC DCCC CM".split(), 1)), 4: dict(enumerate("M MM MMM".split(), 1)), } ROMAN_REGEX = re.compile(r""" (?:(?P<_3000>MMM)|(?P<_2000>MM)|(?P<_1000>M))? (?:(?P<_900>CM)|(?P<_800>DCCC)|(?P<_700>DCC)|(?P<_600>DC) |(?P<_500>D)|(?P<_400>CD)|(?P<_300>CCC)|(?P<_200>CC)|(?P<_100>C))? (?:(?P<_90>XC)|(?P<_80>LXXX)|(?P<_70>LXX)|(?P<_60>LX) |(?P<_50>L)|(?P<_40>XL)|(?P<_30>XXX)|(?P<_20>XX)|(?P<_10>X))? (?:(?P<_9>IX)|(?P<_8>VIII)|(?P<_7>VII)|(?P<_6>VI) |(?P<_5>V)|(?P<_4>IV)|(?P<_3>III)|(?P<_2>II)|(?P<_1>I))? $ """, re.VERBOSE | re.IGNORECASE) def roman_to_int(roman): """ >>> roman_to_int("XI") 11 >>> roman_to_int("MDCCCLXXXVIII") 1888 >>> roman_to_int("MMMCMXCIX") 3999 >>> roman_to_int("McmXLv") 1945 >>> roman_to_int("CCCC") Traceback (most recent call last): ValueError: 'CCCC' is not valid roman >>> roman_to_int("A") Traceback (most recent call last): ValueError: 'A' is not valid roman >>> roman_to_int("") Traceback (most recent call last): ValueError: '' is not valid roman """ if not roman: raise ValueError("{} is not valid roman".format(repr(roman))) m = ROMAN_REGEX.match(roman) if m is None: raise ValueError("{} is not valid roman".format(repr(roman))) ret = 0 for key, value in m.groupdict().items(): if value is not None: ret += int(key[1:]) assert ret >= 0 return ret def int_to_roman(n): """ >>> int_to_roman(11) 'XI' >>> int_to_roman(3999) 'MMMCMXCIX' >>> int_to_roman(1888) 'MDCCCLXXXVIII' >>> int_to_roman(4000) Traceback (most recent call last): ValueError: 4000 is not in range(1, 4000) >>> int_to_roman(0) Traceback (most recent call last): ValueError: 0 is not in range(1, 4000) >>> int_to_roman(0.1) Traceback (most recent call last): TypeError: 0.1 is not integer >>> int_to_roman("10") Traceback (most recent call last): TypeError: '10' is not integer >>> """ if not isinstance(n, int): raise TypeError("{} is not integer".format(repr(n))) if n not in range(1, 4000): raise ValueError("{} is not in range(1, 4000)".format(repr(n))) strs = for digit, x in enumerate(str(n)[::-1], 1): x = int(x) if x > 0: strs.append(DIGIT_STRINGS[digit][x]) return "".join(reversed(strs)) def int_to_digits(n, base=10): """ >>> int_to_digits(0) >>> int_to_digits(1) [1] >>> int_to_digits(12345) [5, 4, 3, 2, 1] >>> int_to_digits(0, base=2) >>> int_to_digits(1, base=2) [1] >>> int_to_digits(2, base=2) [0, 1] >>> int_to_digits(0b1011, base=2) [1, 1, 0, 1] >>> int_to_digits(3**4, base=3) [0, 0, 0, 0, 1] >>> int_to_digits(-1) Traceback (most recent call last): ValueError: -1 is not >= 0 >>> int_to_digits(1.0) Traceback (most recent call last): TypeError: 1.0 is not integer """ if not isinstance(n, int): raise TypeError("{} is not integer".format(repr(n))) if not isinstance(base, int): raise TypeError("base {} is not integer".format(repr(base))) if n < 0: raise ValueError("{} is not >= 0".format(repr(n))) if base < 2: raise ValueError("base {} is not >= 2".format(repr(base))) ret = ret_append = ret.append while n: ret_append(n % base) n //= base return ret if __name__ == "__main__": import doctest doctest.testmod()
docstringに書いてあるように、エラー処理もしてあります。