在Python中将罗马数字转换为整数

19

根据user2486的建议,这是我当前的代码。

def romanMap():
    map=(("M",  1000),("CM", 900),("D",  500),("CD", 400),("C",  100),("XC", 90),("L",  50),("XL", 40),("X",  10),("IX", 9),("V",  5),("V", 4),("I",  1))
    return map
firstNum=ns([0])
secondNum=ns([1])
def main():
    ns=str(input("Enter a roman numeral"))
    total=0
    result=0
    while ns:
        firstNum=(romanMap(ns[0]))
         secondNum=(romanMap(ns[1]) 
        if firstNum is len(ns)>1 or secondNum-1:
                        total=total+firstNum
            ns=ns[1:]
        else:
                        total=total+ns[1]-ns[0]
            ns=ns[2:]
      print (total)
main()

我在使用 while ns: 时遇到了以下错误:UnboundLocalError: local variable 'ns' referenced before assignment。


3
这是一种繁琐且较为困难的方法,如果使用词典的话会更加高效。你可以参考已经编写好的功能代码来实现,链接为:http://svn.python.org/projects/python/branches/pep-0384/Doc/tools/roman.py - user1786283
9
我想象不出那些函数正在做你想让它们做的事情。 - roippi
2
@roippi -- 当然不是。如果是那样,提问者就不会来这里问问题了 :) - mgilson
1
@roippi 不,你可以发起一个关于用回收的土豆制造房屋的众筹活动,并利用这笔资金解决你的问题。 - kojiro
请不要对问题进行如此大的修改 - 而是创建一个新问题!无论如何,“UnboundLocalError”意味着变量尚未被分配并且已经尝试使用它!在这种情况下,缺少从用户输入到ns的赋值。还要注意1)如果len(ns)== 1,则ns [1]可能会引发异常;2)循环外的初始赋值firstNum / secondNum没有任何作用;3)总数应仅从firstNum / secondNum计算,因为ns [x]返回一个字符串;4)实现一个名为“numberOfNumeral”的函数,执行我建议的操作,并使用它;) - user2864740
显示剩余2条评论
17个回答

0

这是我使用字典想出来的东西。它应该很简单。告诉我你的想法。我必须说它不能处理以MIM形式书写的欺骗罗马数字(而不是1999年的MCMXCIX)。这只适用于有效的罗马数字。

import re
s = 0;
a = dict();
b = dict();
r = "MMCMXCVIII"

a['CM'] = 900;
a['IX'] = 9;
a ['IV'] = 4;
a ['XL'] = 40;
a ['CD'] = 400;
a ['XC'] = 90;

b['M'] = 1000;
b['C'] = 100;
b['D'] = 500;
b['X'] = 10;
b['V'] = 5;
b['L'] = 50;
b['I'] = 1;

# Handle the tricky 4's and 9's first and remove them from the string

for key in a:
        if key in r: 
            r = re.sub(key,'',r)
            s+=a[key];
# Then straightforward multiplication of the not-so-tricky ones by their count.

for key in b:
         s+= r.count(key) * b[key];

print s; # This will print 2998

0
roman_conver=[  (1,'I'),
                (5,'V'),
                (10,'X'),
                (50,'L'),
                (100,'C'),
                (500,'D'),
                (1000,'M'),
                    ]
def romantonumeral(roman):
    tot = 0
    for i in range(0,len(roman)):
        for each in roman_conver:
            if roman[i]==each[1]:
                if each[0]>tot:
                    tot = each[0] - tot
                else:
                    tot = tot + each[0]
    return tot

0

在Mark Pilgrim的Dive Into Python 3中,对罗马数字转换器的开发有非常详细的描述。请参见5.3.案例研究:罗马数字,介绍了问题和详细信息。

但这还不是全部。请参见第9章 单元测试,其中包括有关罗马数字转换器的分析和实现,包括有趣的优化和异常抛出--即(单元)测试驱动开发。

这与enginefree在问题下方的第一条评论中提到的代码直接相关(该代码由Mark Pilgrim编写)。


0
你可以使用这段代码:

def roman_integer(roman):
    roman = roman.upper() # for taking care of upper or lower case letters
    integer_rep = 0
    roman_to_integer_map = tuple()
    roman_to_integer_map = (('M',1000),
                            ('CM',900),
                            ('D',500),
                            ('CD',400),
                            ('C',100),
                            ('XC',90),
                            ('L',50),
                            ('XL',40),
                            ('X',10),
                            ('IX',9),
                            ('V',5),
                            ('IV',4),
                            ('I',1))
    roman_numeral_pattern = re.compile("""
    ^                   # beginning of string
    M{0,4}              # thousands - 0 to 4 M's
    (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
                        #            or 500-800 (D, followed by 0 to 3 C's)
    (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
                        #        or 50-80 (L, followed by 0 to 3 X's)
    (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
                        #        or 5-8 (V, followed by 0 to 3 I's)
    $                   # end of string
    """ ,re.VERBOSE)

    if not roman_numeral_pattern.search(roman):
        return 0
    index = 0
    for numeral, integer in roman_to_integer_map:
        while roman[index:index+len(numeral)] == numeral:
            #print numeral, integer, 'matched'
            integer_rep += integer
            index += len(numeral)
    return integer_rep


0
def romanToInt(self, s: str) -> int:
    roman_dict = {'I':1, 'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':1000}
    int_equ = 0

    for i in range(len(s)):
        if i > 0 and roman_dict[s[i]] > roman_dict[s[i-1]]:
            int_equ += roman_dict[s[i]] - 2*roman_dict[s[i-1]]
        else:
            int_equ += roman_dict[s[i]]

    return int_equ

运行时间为48毫秒。 - Shyambeer Singh

0

从罗马数字的右侧开始按顺序相加或相减。很容易。

def rome(roman_num):
     d = {'I':1,'V':5,'X':10,'L':50,'C':100,'D':500,'M':1000}
     nl = list(roman_num)
     sum = d[nl[len(nl)-1]]
     for i in range(len(nl)-1,0,-1):
             if d[nl[i]]>d[nl[i-1]]:
                     sum -= d[nl[i-1]]
             else:
                     sum += d[nl[i-1]]       
     return sum

-3

试一下这个:

def translate(string):
    values = {"i":1, "v":5, "x":10, "l":50, "c":100, "m":1000}
    return sum(map(lambda x: values[x], string))

Lambda代表一行函数。这就是为什么它们被称为匿名函数。您不必在外部使用def和所有形式化定义它们。

您可以在shell上键入以下内容:

f = lambda x: x + 3 f(3) 6 或者 f = lambda x,y: x + y f("foo", "bar") 'foobar'

我正在使用map将我的新生函数应用于可迭代的每个元素。在这种情况下,可迭代的是一个字符串,如“mclvii”。这样做会生成一个列表,其中每个值都是其相应值。看一个计算平方的lambda示例:

>>> a = [1,2,3,4]
>>> square = lambda x: x**2
>>> l = map(square, a)
>>> l = [1,4,9,16]

因此,当您需要即时创建一个函数时,可以使用lambda,而当您想要将一个函数应用于列表中的所有元素时,则可以使用map。

现在,让我们使用递归来举个例子:

def translate2(string):
    values = {"i":1, "v":5, "x":10, "l":50, "c":100, "m":1000}
    if not string:
        return 0
    return values[string[0]] + translate2(string[1:])

1
在这里使用lambda函数只会让事情变得更加复杂。如果你使用列表推导式而不是map,你可以直接使用表达式。如果你真的想要一个函数,它已经存在于operator中,所以你不需要重新创建它。 - abarnert
1
答案错误。请删除此答案。 - DollarAkshay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接