关于python:将整数转换为罗马数字的基本程序?

Basic program to convert integer to Roman numerals?

我正试图编写一个代码,将用户输入的整数转换成它的罗马数字等价物。到目前为止,我拥有的是:

screenshot of my code

generate_all_of_numeral函数的作用点是为每个特定的数字创建一个字符串。例如,generate_all_of_numeral(2400, 'M', 2000)将返回字符串'MM'

我正在努力完成主计划。我首先找到m的罗马数字计数,然后将其保存到变量m中,然后减去m的个数乘以符号值,得到下一个要处理的最大数字的值。

有没有向正确的方向点头?现在我的代码甚至都不打印任何东西。


处理这一问题的最佳方法之一是使用divmod函数。您可以检查给定的数字是否与从最高到最低的任何罗马数字匹配。在每次匹配时,您都应该返回各自的字符。

在使用模函数时,有些数字会有余数,因此您也会对余数应用相同的逻辑。显然,我在暗示递归。

请看下面我的答案。我使用OrderedDict来确保可以"向下"迭代列表,然后使用divmod的递归来生成匹配项。最后,我join都生成了一个字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from collections import OrderedDict

def write_roman(num):

    roman = OrderedDict()
    roman[1000] ="M"
    roman[900] ="CM"
    roman[500] ="D"
    roman[400] ="CD"
    roman[100] ="C"
    roman[90] ="XC"
    roman[50] ="L"
    roman[40] ="XL"
    roman[10] ="X"
    roman[9] ="IX"
    roman[5] ="V"
    roman[4] ="IV"
    roman[1] ="I"

    def roman_num(num):
        for r in roman.keys():
            x, y = divmod(num, r)
            yield roman[r] * x
            num -= (r * x)
            if num <= 0:
                break

    return"".join([a for a in roman_num(num)])

旋转一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
num = 35
print write_roman(num)
# XXXV

num = 994
print write_roman(num)
# CMXCIV

num = 1995
print write_roman(num)
# MCMXCV

num = 2015
print write_roman(num)
# MMXV


这是另一种没有划分的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
num_map = [(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 num2roman(num):

    roman = ''

    while num > 0:
        for i, r in num_map:
            while num >= i:
                roman += r
                num -= i

    return roman

# test
>>> num2roman(2242)
'MMCCXLII'


曼哈顿算法的KISS版本,没有任何"高级"概念,如OrderedDict、递归、生成器、内部函数和break

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ROMAN = [
    (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 int_to_roman(number):
    result =""
    for (arabic, roman) in ROMAN:
        (factor, number) = divmod(number, arabic)
        result += roman * factor
    return result

一旦number达到零,就可以添加一个不饱和出口,字符串的积累可以使更多的Python,但我的目标是生成所需的基本程序。

对1到100000之间的所有整数进行测试,这对任何人都是足够的。

编辑:我提到的略多的Python和更快的版本:

1
2
3
4
5
6
7
8
def int_to_roman(number):
    result = []
    for (arabic, roman) in ROMAN:
        (factor, number) = divmod(number, arabic)
        result.append(roman * factor)
        if number == 0:
            break
    return"".join(result)


我参考了这个网址进行在线十进制到罗马的转换。如果我们将小数的范围扩展到3999999,@manhattan给出的脚本将不起作用。以下是3999999范围内的正确脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def int_to_roman(num):
    _values = [
        1000000, 900000, 500000, 400000, 100000, 90000, 50000, 40000, 10000, 9000, 5000, 4000, 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]

    _strings = [
        'M', 'C', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV',"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"]

    result =""
    decimal = num

    while decimal > 0:
        for i in range(len(_values)):
            if decimal >= _values[i]:
                if _values[i] > 1000:
                    result += u'\u0304'.join(list(_strings[i])) + u'\u0304'
                else:
                    result += _strings[i]
                decimal -= _values[i]
                break
    return result

unicode字符u'304'打印上横线字符;例如enter image description here

样品输出:

enter image description here


这里有一个lambda函数,用于整数到罗马数字的转换,最大值为3999。它锚定了"你可能实际上不想做的不可读的事情"空间的某个角落。但它可能会取悦某人:

1
2
3
4
5
6
7
8
9
lambda a: (
   "".join(reversed([
     "".join([
         "IVXLCDM"[int(d)+i*2]
          for d in [
             "","0","00","000","01",
             "1","10","100","1000","02"][int(c)]])
          for i,c in enumerate(reversed(str(a))) ]))
     )

这种方法提供了一种使用算术操作的替代方法像op和许多示例一样,隔离十进制数字及其位置。这里的方法是直接将十进制数转换为字符串。这样,可以通过列表索引隔离数字。数据表是公平的压缩,不使用减法或除法。

诚然,在给定的形式中,无论从简洁中获得什么,都是立即的放弃可读性。对于没有时间玩拼图的人,请参阅下面的版本它避免了列表理解和lambda函数。

逐步通过

但我将在这里解释lambda函数的版本…

从后向前:

  • 将十进制整数转换为其数字的反转字符串,并枚举(i)倒过来的数字(c)。

    1
    2
    3
    ....
    for i,c in enumerate(reversed(str(a)))
    ....
  • 将每个数字C转换回一个整数(范围为0-9),并将其用作变位字符串列表的索引。稍后会解释这个魔法。

    1
    2
    3
    4
    ....
    ["","0","00","000","01",
    "1","10","100","1000","02"][int(c)]])
    ....
  • 将选定的魔法数字字符串转换为罗马数字字符串"数字"。基本上,现在您的十进制数字表示为罗马数字与十进制数字的原10位相对应的数字。这是OP使用的generate_all_of_numeral函数的目标。

    1
    2
    3
    4
    5
    ....
    "".join([
       "IVXLCDM"[int(d)+i*2]
        for d in <magic digit string>
    ....
  • 将所有内容按相反的顺序重新连接。颠倒顺序数字,但按数字顺序排列("数字"?)不受影响。

    1
    2
    3
    4
    lambda a: (
       "".join(reversed([
        <roman-numeral converted digits>
        ]))
  • 魔法字符串列表

    现在,关于魔法弦的列表。它允许选择适当的罗马数字串(最多四个,每一个都是0、1或2三种类型中的一种),用于一个十进制数字可以占据的每一个不同的10位。

    • 0 ->""; roman numerals don't show zeros.
    • 1 ->"0"; 0 + 2*i maps to I, X, C or M -> I, X, C or M.
    • 2 ->"00"; like for 1, x2 -> II, XX, CC, MM.
    • 3 ->"000"; like for 1, x3 -> III, XXX, CCC, MMM.
    • 4 ->"01"; like for 1, then 1 +2*i maps to V, L, or D -> IV, XL, CD.
    • 5 ->"1"; maps to odd roman numeral digits -> V, L, D.
    • 6 ->"10"; reverse of 4 -> VI, LX, DC.
    • 7 ->"100"; add another I/X/C -> VII LXX, DCC
    • 8 ->"1000"; add another I/X/C -> VIII, LXXX, DCCC
    • 9 ->"02"; like for 1, plus the next 10's level up (2 + i*2) -> IX, XC, CM.

    在4000及以上,这将引发一个异常。"mmmm"=4000,但这个不再匹配模式,打破了算法的假设。

    重写版本

    …正如上面所承诺的…

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    def int_to_roman(a):
        all_roman_digits = []
        digit_lookup_table = [
           "","0","00","000","01",
           "1","10","100","1000","02"]
        for i,c in enumerate(reversed(str(a))):
            roman_digit =""
            for d in digit_lookup_table[int(c)]:
              roman_digit += ("IVXLCDM"[int(d)+i*2])
            all_roman_digits.append(roman_digit)
        return"".join(reversed(all_roman_digits))

    我再次排除了异常捕获,但至少现在有一个地方可以把它放在行内。


    笑人的方法奏效了。使用有序的词典很聪明。但是他的代码在每次调用函数时都会重新创建有序字典,在函数内部,在每次递归调用中,函数都会从顶部逐步遍历整个有序字典。此外,divmod返回商和余数,但不使用余数。更直接的方法如下。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    def _getRomanDictOrdered():
        #
        from collections import OrderedDict
        #
        dIntRoman = OrderedDict()
        #
        dIntRoman[1000] ="M"
        dIntRoman[900] ="CM"
        dIntRoman[500] ="D"
        dIntRoman[400] ="CD"
        dIntRoman[100] ="C"
        dIntRoman[90] ="XC"
        dIntRoman[50] ="L"
        dIntRoman[40] ="XL"
        dIntRoman[10] ="X"
        dIntRoman[9] ="IX"
        dIntRoman[5] ="V"
        dIntRoman[4] ="IV"
        dIntRoman[1] ="I"
        #
        return dIntRoman

    _dIntRomanOrder = _getRomanDictOrdered() # called once on import

    def getRomanNumeralOffInt( iNum ):
        #
        lRomanNumerals = []
        #
        for iKey in _dIntRomanOrder:
            #
            if iKey > iNum: continue
            #
            iQuotient = iNum // iKey
            #
            if not iQuotient: continue
            #
            lRomanNumerals.append( _dIntRomanOrder[ iKey ] * iQuotient )
            #
            iNum -= ( iKey * iQuotient )
            #
            if not iNum: break
            #
        #
        return ''.join( lRomanNumerals )

    检查结果:

    1
    2
    3
    4
    5
    6
    7
    8
    >>> getRomanNumeralOffInt(35)
    'XXXV'
    >>> getRomanNumeralOffInt(994)
    'CMXCIV'
    >>> getRomanNumeralOffInt(1995)
    'MCMXCV'
    >>> getRomanNumeralOffInt(2015)
    'MMXV'


    我注意到,在大多数答案中,人们都在存储多余的符号,如"IX" for 9"XL" for 40等。

    这遗漏了罗马转化的主要本质。

    在我真正粘贴代码之前,这里有一个小的介绍和算法。

    The original pattern for Roman numerals used the symbols I, V. and X (1, 5, and 10) as simple tally marks. Each marker for 1 (I) added a unit value up to 5 (V), and was then added to (V) to make the numbers from 6 to 9:

    I, II, III, IIII, V, VI, VII, VIII, VIIII, X.

    The numerals for 4 (IIII) and 9 (VIIII) proved problematic, and are generally replaced with IV (one less than 5) and IX (one less than 10). This feature of Roman numerals is called subtractive notation.

    The numbers from 1 to 10 (including subtractive notation for 4 and 9) are expressed in Roman numerals as follows:

    I, II, III, IV, V, VI, VII, VIII, IX, X.

    The system being basically decimal, tens and hundreds follow the same pattern:
    Thus 10 to 100 (counting in tens, with X taking the place of I, L taking the place of V and C taking the place of X):

    X, XX, XXX, XL, L, LX, LXX, LXXX, XC, C. Roman Numerals - Wikipedia

    因此,从上面的介绍中可以得出的主要逻辑是,我们将去掉位置值,并根据所使用的罗马文字值进行划分。

    让我们从基本示例开始。我们有完整的文字列表,如[10, 5, 1]

  • 1/10=0.1(不多用)

    1/5=0.2(也不多用)

    1/1=1.0(嗯,我们有东西!)

    例1:所以,如果商=1,则打印与整数对应的文本。所以,最好的数据结构是字典。{10:"X", 5:"V", 1:"I"}

    "我"将被打印出来。

  • 2/10=0.2

    2/5=0.4

    2/1=2

    例2:所以,如果商>1,打印与整数相对应的文字,然后从数字中减去它。这使得它是1,它属于案例1。打印"II"。

  • 3/10=0.3

    3/5=0.6

    3/1=3

    因此,案例2:"i",案例2:"i i",案例1:"i i i"

  • 例3:加1,检查商是否等于1。

    (4±1)/ 10=0.5

    (4±1)/ 5=1

    在这种情况下,我们首先减去除数和数字,然后打印与结果相对应的文字,然后是除数。5-4=1,打印"四"。

  • (9±1)/ 10=1

    10-9=1。打印"i",打印"x",即"i x"

  • 这延伸到十分之一的地方和百分之一。

  • (90+(10^1))/100=1.

    打印100-90="x",然后打印100="c"。

  • (400+(10^2))/500=1.

    打印500-400="c",然后打印500="d"。

  • 这里我们最不需要的是提取位置值。例:449应产生400、40、9。

    这可以通过去掉10^(位置-1)的模,然后取10^位置的模来实现。

    例:449,位置=2:449%(10^1)=9->449-9->440%(10^2)=40。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    '''
    Created on Nov 20, 2017

    @author: lu5er
    '''

    n = int(input())
    ls = [1000, 500, 100, 50, 10, 5, 1]
    st = {1000:"M", 500:"D", 100:"C", 50:"L", 10:"X", 5:"V", 1:"I"}

    rem = 0

    # We traverse the number from right to left, extracting the position
    for i in range(len(str(n)), 0, -1):
        pos = i # stores the current position
        num = (n-n%(10**(pos-1)))%(10**pos) # extracts the positional values
        while(num>0):
            for div in ls:

                # CASE 1: Logic for 1, 5 and 10
                if num/div == 1:
                    #print("here")
                    print(st[div], end="")
                    num-=div
                    break

                # CASE 2: logic for 2, 3, 6 and 8
                if num/div > 1:
                    print(st[div],end="")
                    num-=div
                    break

                # CASE 3: Logic for 4 and 9
                if (num+(10**(pos-1)))/div == 1:
                    print(st[div-num], end="")
                    print(st[div], end="")
                    num-=div
                    break

    输出测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    99
    XCIX

    499
    CDXCIX

    1954
    MCMLIV

    1990
    MCMXC

    2014
    MMXIV

    35
    XXXV

    994
    CMXCIV

    只有1—999

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    while True:

     num = input()
     def val(n):
        if n == 1:
            rom = 'I'
            return rom
        if n == 4:
            rom = 'IV'
            return rom
        if n == 5:
            rom = 'V'
            return rom
        if n == 9:
            rom = 'IX'
            return rom
        if n == 10:
            rom = 'X'
            return rom
        if n == 40:
            rom = 'XL'
            return rom
        if n == 50:
            rom = 'L'
            return rom
        if n == 90:
            rom = 'XC'
            return rom
        if n == 100:
            rom = 'C'
            return rom
        if n == 400:
            rom = 'CD'
            return rom
        if n == 500:
            rom = 'D'
            return rom
        if n == 900:
            rom = 'CM'
            return rom

     def lastdigit(num02):
        num02 = num % 10
        num03 = num % 5
        if 9 > num02 > 5:
            return str('V' + 'I'*num03)
        elif num02 < 4:
            return str('I'*num03)
        else:
            return str(val(num02))

     k3 = lastdigit(num)

     def tensdigit(num12):
        num12 = num % 100 - num % 10
        num13 = num % 50
        if 90 > num12 > 50:
            return str('L' + 'X'*(num13/10))
        elif num12 < 40:
            return str('X'*(num13/10))
        else:
            return str(val(num12))

     k2 = tensdigit(num)

     def hundigit(num112):
        num112 = (num % 1000 - num % 100)
        num113 = num % 500
        if 900 > num112 > 500:
            return str('D' + 'C'*(num113/100))
        elif num112 < 400:
            return str('C'*(num113/100))
        else:
            return str(val(num112))

     k1 = hundigit(num)

     print '%s%s%s' %(k1,k2,k3)

    另一种方法。从4、9等开始对数字进行分离处理。可以进一步简化

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    def checkio(data):
    romans = [("I",1),("V",5),("X",10),("L",50),("C",100),("D",500),("M",1000)]
    romans_rev = list(sorted(romans,key = lambda x: -x[1]))
    def process_9(num,roman_str):
        for (k,v) in romans:
            if (v > num):
                current_roman = romans[romans.index((k,v))]
                prev_roman = romans[romans.index((k,v)) - 2]
                roman_str += (prev_roman[0] + current_roman[0])
                num -= (current_roman[1] - prev_roman[1])
                break
        return num,roman_str
    def process_4(num,roman_str):
        for (k,v) in romans:
            if (v > num):
                current_roman = romans[romans.index((k,v))]
                prev_roman = romans[romans.index((k,v)) - 1]
                roman_str += (prev_roman[0] + current_roman[0])
                num -= (current_roman[1] - prev_roman[1])
                break
        return num,roman_str
    def process_other(num,roman_str):
        for (k,v) in romans_rev:
            div = num // v
            if ( div != 0 and num > 0 ):
                roman_str += k * div
                num -= v * div
                break
        return num,roman_str
    def get_roman(num):
        final_roman_str =""
        while (num > 0):
            if (str(num).startswith('4')):
                num,final_roman_str = process_4(num,final_roman_str)
            elif(str(num).startswith('9')):
                num,final_roman_str = process_9(num,final_roman_str)
            else:
                num,final_roman_str = process_other(num,final_roman_str)
        return final_roman_str

    return get_roman(data)


    print(checkio(number))

    必须使符号计数成为全局变量。在打印方法中使用()。


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    def test(num):

        try:
            if type(num) != type(1):
                raise Exception("expected integer, got %s" % type(num))
            if not 0 < num < 4000:
                raise Exception("Argument must be between 1 and 3999")
            ints = (1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1)
            nums = ('M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I')
            result =""
            for i in range(len(ints)):
                count = int(num / ints[i])
                result += nums[i] * count
                num -= ints[i] * count
            print result
        except Exception as e:
            print e.message


    另一种方式。我用罗马符号写了递归循环,所以递归的最大深度等于罗马元组的长度:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    ROMAN = ((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 get_romans(number):
        return do_recursive(number, 0, '')


    def do_recursive(number, index, roman):
        while number >= ROMAN[index][0]:
            number -= ROMAN[index][0]
            roman += ROMAN[index][1]
        if number == 0:
            return roman
        return check_recursive(number, index + 1, roman)


    if __name__ == '__main__':
        print(get_romans(7))
        print(get_romans(78))

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    roman_map = [(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 IntToRoman (xn):
        x = xn
        y = 0
        Str =""
        for i, r in roman_map:
             # take the number and divisible by the roman number from 1000 to 1.
            y = x//i    

            for j in range(0, y):
                # If after divisibility is not 0 then take the roman number from list into String.
                Str = Str+r

            # Take the remainder to next round.
            x = x%i
        print(Str)
        return Str

    测试用例:

    1
    2
    3
    >>> IntToRoman(3251)
    MMMCCLI
    'MMMCCLI'

    开始减去1000000…从a到1,当它为正数时停止。将相应的罗马字母添加到ans并使a到a-i,其中i是(1,4,5,9,10…)重复,而a不变为0。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    def intToRoman(self, A):
        l=[[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']]
        ans=""
        while(A>0):
            for i,j in l[::-1]:
                if A-i>=0:
                    ans+=j
                    A=A-i
                    break
        return ans


    这是我将一个数转换为它的罗马等价物的递归函数方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
        def solution(n):
            # TODO convert int to roman string
            string=''
            symbol=['M','D','C','L','X','V','I']
            value = [1000,500,100,50,10,5,1]
            num = 10**(len(str(n))-1)
            quo = n//num
            rem=n%num
            if quo in [0,1,2,3]:
                string=string+symbol[value.index(num)]*quo
            elif quo in [4,5,6,7,8]:
                tem_str=symbol[value.index(num)]+symbol[value.index(num)-1]
                        +symbol[value.index(num)]*3
                string=string+tem_str[(min(quo,5)-4):(max(quo,5)-3)]
            else:
                string=string+symbol[value.index(num)]+symbol[value.index(num)-2]
            if rem==0:
                return string
            else:
                string=string+solution(rem)
            return string

    print(solution(499))
    print(solution(999))
    print(solution(2456))
    print(solution(2791))
    CDXCIX
    CMXCIX
    MMCDLVI
    MMDCCXCI

    我将此转换作为kata练习进行,并提出了一个利用python字符串操作的解决方案:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    from collections import namedtuple

    Abbreviation = namedtuple('Abbreviation', 'long short')
    abbreviations = [
        Abbreviation('I' * 1000, 'M'),
        Abbreviation('I' * 500, 'D'),
        Abbreviation('I' * 100, 'C'),
        Abbreviation('I' * 50, 'L'),
        Abbreviation('I' * 10, 'X'),
        Abbreviation('I' * 5, 'V'),
        Abbreviation('DCCCC', 'CM'),
        Abbreviation('CCCC', 'CD'),
        Abbreviation('LXXXX', 'XC'),
        Abbreviation('XXXX', 'XL'),
        Abbreviation('VIIII', 'IX'),
        Abbreviation('IIII', 'IV')
    ]


    def to_roman(arabic):
        roman = 'I' * arabic
        for abbr in abbreviations:
            roman = roman.replace(abbr.long, abbr.short)

        return roman

    我喜欢它的简单!不需要模运算、条件或多个循环。当然,您也不需要namedtuple;您可以使用纯元组或列表。


    这是我的递归方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    def itr(num):
            if(num == 1): return"I"
            if(num == 4): return"IV"
            if(num == 5): return"V"
            if(num == 9):  return"IX"
            if(num == 10): return"X"
            if(num == 40): return"XL"
            if(num == 50): return"L"
            if(num == 90): return"XC"
            if(num == 100): return"C"
            if(num == 400): return"CD"
            if(num == 500): return"D"        
            if(num == 900): return"CM"
            if(num == 1000): return"M"        

            for i in [1000, 100, 10, 1]:            
                for j in [9*i, 5*i, 4*i, i]:
                    if(num>=j):
                        return itr(j) + itr(num-j)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    """
    # This program will allow the user to input a number from 1 - 3999 (in english) and will translate it to Roman numerals.
    # sources: http://romannumerals.babuo.com/roman-numerals-100-1000
    Guys the reason why I wrote this program like that so it becomes readable for everybody.
    Let me know if you have any questions...
    """

    while True:
        try:
            x = input("Enter a positive integer from 1 - 3999 (without  spaces) and this program will translated to Roman numbers:")
            inttX = int(x)
            if (inttX) == 0 or 0 > (inttX):
                print("Unfortunately, the  smallest number that you can enter is 1")
            elif (inttX) > 3999:
                print("Unfortunately, the  greatest number that you can enter is 3999")
            else:
                if len(x) == 1:
                    if inttX == 1:
                        first ="I"
                    elif inttX == 2:
                        first ="II"
                    elif inttX == 3:
                        first ="III"
                    elif inttX == 4:
                        first ="IV"
                    elif inttX == 5:
                        first ="V"
                    elif inttX == 6:
                        first ="VI"
                    elif inttX == 7:
                        first ="VII"
                    elif inttX == 8:
                        first ="VIII"
                    elif inttX == 9:
                        first ="IX"
                    print(first)
                    break
                if len(x) == 2:
                    a = int(x[0])
                    b = int(x[1])
                    if a == 0:
                        first =""
                    elif a == 1:
                        first ="X"
                    elif a == 2:
                        first ="XX"
                    elif a == 3:
                        first ="XXX"
                    elif a == 4:
                        first ="XL"
                    elif a == 5:
                        first ="L"
                    elif a == 6:
                        first ="LX"
                    elif a == 7:
                        first ="LXX"
                    elif a == 8:
                        first ="LXXX"
                    elif a == 9:
                        first ="XC"

                    if b == 0:
                        first1 ="0"
                    if b == 1:
                        first1 ="I"
                    elif b == 2:
                        first1 ="II"
                    elif b == 3:
                        first1 ="III"
                    elif b == 4:
                        first1 ="IV"
                    elif b == 5:
                        first1 ="V"
                    elif b == 6:
                        first1 ="VI"
                    elif b == 7:
                        first1 ="VII"
                    elif b == 8:
                        first1 ="VIII"
                    elif b == 9:
                        first1 ="IX"
                    print(first + first1)
                    break
                if len(x) == 3:
                    a = int(x[0])
                    b = int(x[1])
                    c = int(x[2])
                    if a == 0:
                        first12 =""
                    if a == 1:
                        first12 ="C"
                    elif a == 2:
                        first12 ="CC"
                    elif a == 3:
                        first12 ="CCC"
                    elif a == 4:
                        first12 ="CD"
                    elif a == 5:
                        first12 ="D"
                    elif a == 6:
                        first12 ="DC"
                    elif a == 7:
                        first12 ="DCC"
                    elif a == 8:
                        first12 ="DCCC"
                    elif a == 9:
                        first12 ="CM"

                    if b == 0:
                        first =""
                    elif b == 1:
                        first ="X"
                    elif b == 2:
                        first ="XX"
                    elif b == 3:
                        first ="XXX"
                    elif b == 4:
                        first ="XL"
                    elif b == 5:
                        first ="L"
                    elif b == 6:
                        first ="LX"
                    elif b == 7:
                        first ="LXX"
                    elif b == 8:
                        first ="LXXX"
                    elif b == 9:
                        first ="XC"

                    if c == 1:
                        first1 ="I"
                    elif c == 2:
                        first1 ="II"
                    elif c == 3:
                        first1 ="III"
                    elif c == 4:
                        first1 ="IV"
                    elif c == 5:
                        first1 ="V"
                    elif c == 6:
                        first1 ="VI"
                    elif c == 7:
                        first1 ="VII"
                    elif c == 8:
                        first1 ="VIII"
                    elif c == 9:
                        first1 ="IX"
                    print(first12 + first + first1)
                    break

                if len(x) == 4:
                    a = int(x[0])
                    b = int(x[1])
                    c = int(x[2])
                    d = int(x[3])
                    if a == 0:
                        first1 =""
                    if a == 1:
                        first1 ="M"
                    elif a == 2:
                        first1 ="MM"
                    elif a == 3:
                        first1 ="MMM"

                    if b == 0:
                        first12 =""
                    if b == 1:
                        first12 ="C"
                    elif b == 2:
                        first12 ="CC"
                    elif b == 3:
                        first12 ="CCC"
                    elif b == 4:
                        first12 ="CD"
                    elif b == 5:
                        first12 ="D"
                    elif b == 6:
                        first12 ="DC"
                    elif b == 7:
                        first12 ="DCC"
                    elif b == 8:
                        first12 ="DCCC"
                    elif b == 9:
                        first12 ="CM"

                    if c == 0:
                        first3 =""
                    elif c == 1:
                        first3 ="X"
                    elif c == 2:
                        first3 ="XX"
                    elif c == 3:
                        first3 ="XXX"
                    elif c == 4:
                        first3 ="XL"
                    elif c == 5:
                        first3 ="L"
                    elif c == 6:
                        first3 ="LX"
                    elif c == 7:
                        first3 ="LXX"
                    elif c == 8:
                        first3 ="LXXX"
                    elif c == 9:
                        first3 ="XC"

                    if d == 0:
                        first =""
                    elif d == 1:
                        first ="I"
                    elif d == 2:
                        first ="II"
                    elif d == 3:
                        first ="III"
                    elif d == 4:
                        first ="IV"
                    elif d == 5:
                        first ="V"
                    elif d == 6:
                        first ="VI"
                    elif d == 7:
                        first ="VII"
                    elif d == 8:
                        first ="VIII"
                    elif d == 9:
                        first ="IX"
                    print(first1 + first12 + first3 + first)
                    break
        except ValueError:
            print(" Please enter a positive integer!")

    使用def关键字时,只需定义一个函数,但不运行它。

    你要找的是这样的东西:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def generate_all_numerals(n):
    ...

    def to_roman(n):
    ...

    print"This program ..."
    n = raw_input("Enter...")

    print to_roman(n)

    欢迎使用python:)