现在这是我用来表示用户2486之后的当前代码。
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()
我在ns时收到此错误: UnboundLocalError:在赋值之前引用的局部变量'ns'
答案 0 :(得分:19)
无需重新发明轮子(除非你想)。 Python附带一个转换器:
import roman;
n=roman.fromRoman("X"); #n becomes 10
如果您需要数字5000及以上,您需要编写一个新功能,并且可能会使用您自己的字体来表示罗马数字上的线条。 (它只适用于某些数字,停在4999是一个非常好的主意。)
要转换为罗马数字,请使用roman.toRoman(myInt)
。
其他人实际上链接到罗马模块在上述评论中使用的相同源代码,但我不相信他们提到它实际上是Python。
编辑:请注意,在某些系统(Windows,我认为)上,您无法从默认安装中键入import roman
。但是,源代码仍可在Windows上运行,并且它包含在此位置的Python 3.4.1源代码下载(可能也是早期版本)/Python-3.4.1/Doc/tools/roman.py
答案 1 :(得分:6)
当您添加或减去每个符号的值时,从左到右读取罗马数字。
如果某个值低于以下值,则会减去该值。否则会被添加。
例如,我们希望将罗马数字MCMLIV转换为阿拉伯数字:
M = 1000 must be added, because the following letter C =100 is lower.
C = 100 must be subtracted because the following letter M =1000 is greater.
M = 1000 must be added, because the following letter L = 50 is lower.
L = 50 must be added, because the following letter I =1 is lower.
I = 1 must be subtracted, because the following letter V = 5 is greater.
V = 5 must be added, because there are no more symbols left.
我们现在可以计算出数字:
1000 - 100 + 1000 + 50 - 1 + 5 = 1954
参考:http://www.mathinary.com/roman_numerals_from_roman_numerals_to_arabic_numbers.jsp
def from_roman(num):
roman_numerals = {'I':1, 'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':1000}
result = 0
for i,c in enumerate(num):
if (i+1) == len(num) or roman_numerals[c] >= roman_numerals[num[i+1]]:
result += roman_numerals[c]
else:
result -= roman_numerals[c]
return result
答案 2 :(得分:4)
考虑这个额外的伪代码和提示(其中一些是有效的Python,有些不是,但有注释)。
def numberOfNumeral(n):
""" Return the number represented by the single numeral """
# e.g. "v" -> 5, "i" -> 5 (and handle v/V cases, etc.)
# avoid "string" as a variable name
# I chose "ns" for "numerals" (which might be better),
# but I'm also a bit terse .. anyway, name variables for what they represents.
ns = str(input("Enter a roman numeral"))
while ns:
firstNum = numberOfNumeral(ns[0])
# This makes secondValue = -1 when there is only one numeral left
# so firstNum is always "at least" secondNum when len(ns) == 1.
secondNum = numberOfNumeral(ns[1]) if len(ns) > 1 else -1
if firstNum is at least secondNum:
# Add firstNum to total.
# Remove the character - so that the loop state advances.
# If we don't don't his, as in the original, it will never end.
# Here we use "slice notation".
ns = ns[1:]
else:
# Add the difference, secondNum - firstNum, to total.
# Remove both characters - again, so we advance state.
ns = ns[2:]
答案 3 :(得分:3)
这是我的解决方案:
numerals = [
{'letter': 'M', 'value': 1000},
{'letter': 'D', 'value': 500},
{'letter': 'C', 'value': 100},
{'letter': 'L', 'value': 50},
{'letter': 'X', 'value': 10},
{'letter': 'V', 'value': 5},
{'letter': 'I', 'value': 1},
]
def arabic_to_roman(number):
remainder = number
result = ''
for numeral_index in xrange(len(numerals)):
numeral = numerals[numeral_index]
next_numeral = numerals[numeral_index + 1] if numeral_index + 1 < len(numerals) else None
factor = remainder / numeral['value']
remainder -= factor * numeral['value']
if next_numeral:
numeral_difference = numeral['value'] - next_numeral['value']
if (remainder - numeral_difference >= 0) and (numeral_difference > next_numeral['value']):
result += next_numeral['letter'] + numeral['letter']
remainder -= numeral_difference
if factor > 0:
result += numeral['letter'] * factor
return result
def roman_to_arabic(number):
index_by_letter = {}
for index in xrange(len(numerals)):
index_by_letter[numerals[index]['letter']] = index
result = 0
previous_value = None
for letter in reversed(number):
index = index_by_letter[letter]
value = numerals[index]['value']
if (previous_value is None) or (previous_value <= value):
result += value
else:
result -= value
previous_value = value
return result
答案 4 :(得分:2)
好的,你现在拥有的东西有很多不妥之处。
首先,你得到一堆0的原因是因为你永远不会退出你的while string != "":
循环,并且它总是不会在整数中添加整数。因此total
保持为零,并且不断打印。我已经评论了您发布的代码,以帮助您了解正在发生的事情。
def main():
string=str(input("Enter a roman numeral"))
total=0
while string != "": # Empty strings evaluate as False, this can just be 'while string:'
if string[1] == string[2] or string == len([1]): # Here you are testing the 2nd and 3rd elements.
# Also, you want to do len(string) == 1
# string will never == len([1]), so you never
# execute the code in this block.
total += string[1]+1 # You want to add the corresponding value of string[0], use a dictionary.
print (total)
# Missing the else statement in the pseudocode.
main()
user2864740在他们发布的解决方案中有一些很好的评论,看一下你看到的一些错误。
这是Python(不幸的是2.7)代码,可以执行您给定的伪代码所说的内容。
val = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000}
def main():
string = str(raw_input('Enter a roman numeral: '))
string = string.upper()
total = 0
while string:
if len(string) == 1 or val[string[0]] >= val[string[1]]:
total += val[string[0]]
string = string[1:]
else:
total += val[string[1]] - val[string[0]]
string = string[2:]
print total
main()
请注意,您发布的伪代码不正确。请注意它将对输入'IIV'
执行的操作。它将从1减1,然后加5.但它应该做的是从5中减去2。
答案 5 :(得分:2)
一个不错的紧凑版本,没有外部库:
def rn_to_int(s):
d = {'m': 1000, 'd': 500, 'c': 100, 'l': 50, 'x': 10, 'v': 5, 'i': 1}
n = [d[i] for i in s.lower() if i in d]
return sum([i if i>=n[min(j+1, len(n)-1)] else -i for j,i in enumerate(n)])
for numeral, expected in [['CLXIV', 164], ['MDCCLXXXIII', 1783], ['xiv', 14]]:
assert rn_to_int(numeral) == expected
答案 6 :(得分:2)
从右到左的解决方案有点Pythonic(没有索引)而且相对较短。
算法:
示例:
'xiv'
=&gt; sum(5, -1, 10)
=&gt; 14
def parse_roman(s):
numerals = {'M':1000, 'D':500, 'C':100, 'L':50, 'X':10, 'V':5, 'I':1}
n = 0
last_value = 0
# e.g. convert 'xiv' to (5, 1, 10)
for value in (numerals[c] for c in reversed(s.upper())):
# debugging
v = (value, -value)[value < last_value]
print('{:6} += {:5} <== cur, prev = {}, {}'.format(n, v, value, last_value))
# subtract smaller values that come after larger ones, otherwise add
n += (value, -value)[value < last_value]
last_value = value
return n
输出:
parse_roman('MMCMXCVIII')
0 += 1 <== cur, prev = 1, 0
1 += 1 <== cur, prev = 1, 1
2 += 1 <== cur, prev = 1, 1
3 += 5 <== cur, prev = 5, 1
8 += 100 <== cur, prev = 100, 5
108 += -10 <== cur, prev = 10, 100
98 += 1000 <== cur, prev = 1000, 10
1098 += -100 <== cur, prev = 100, 1000
998 += 1000 <== cur, prev = 1000, 100
1998 += 1000 <== cur, prev = 1000, 1000
2998
注意:最好找到一种(短的,内联的)方法来动态改变序列的符号。例如,(5, 1, 10)
==&gt; (5, -1, 10)
。
更新:这与我放弃之前的情况一样接近。它与上面的代码完全相同,但它使用itertools.tee()
和zip()
来生成先前值和当前值的对,以消除对状态变量的需要。对next(cur)
的单次调用使得该列表比prev
更短,这是我们需要确定是添加还是减去当前值的所有状态。
示例:
cur, prev = (5, 1, 10), (5, 1, 10)
# Take one from cur and zip the rest
next(cur) + sum(... zip(cur, prev))
# 5 + ... zip( (1, 10), (5, 1, 10) ) ==> 5 + ... ((1, 5), (10, 1))
代码:
from itertools import tee
def parse_roman(s):
numerals = {'M':1000, 'D':500, 'C':100, 'L':50, 'X':10, 'V':5, 'I':1}
cur, prev = tee(numerals[c] for c in reversed(s.upper()))
return next(cur) + sum((cur, -cur)[cur < prev] for cur, prev in zip(cur,prev))
答案 7 :(得分:1)
这段代码
mapping = {'I': 1, 'V': 5, 'X': 10,'L': 50, 'C': 100, 'D': 500, 'M':1000}
def roman_to_dec(roman):
"""
Convert the roman no to decimal
"""
dec = last = 0
for i in range(0, len(roman)):
no = mapping.get(roman[i])
# subtract last 2 times cuz one for this pass and another for last pass
dec = dec + (no - 2 * last) if no > last else dec + no
last = no
return dec
答案 8 :(得分: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
&#13;
答案 9 :(得分: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
答案 10 :(得分:0)
这是我用词典想出的东西。它应该是v.simple。告诉我你的想法。我必须说它不能处理以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
答案 11 :(得分: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
答案 12 :(得分:0)
Mark Pilgrim对Dive Into Python 3中罗马数字转换器的发展进行了非常详细的描述。请参阅介绍问题和详细信息的5.3. Case Study: Roman Numerals。
但这不是全部。请参阅Chapter 9. Unit Testing,其中罗马数字转换器的分析和实现仍在继续,包括有趣的优化和异常抛出 - (单元)测试驱动开发。
它与enginefree对问题下方第一条评论中代码的引用直接相关(代码由Mark Pilgrim编写)。
答案 13 :(得分:0)
这是一个leetcode问题。
def romanToInt(s):
sum=0
dict={'M':1000,'D':500,'C':100,'L':50,'X':10,'V':5,'I':1}
for i in range(len(s)):
if i==0:
sum=sum+dict[s[i]]
else:
if s[i]=='M':
sum=sum+1000
if s[i-1]=='C':
sum=sum-200
elif s[i]=='D':
sum=sum+500
if s[i-1]=='C':
sum=sum-200
elif s[i]=='C':
sum=sum+100
if s[i-1]=='X':
sum=sum-20
elif s[i]=='L':
sum=sum+50
if s[i-1]=='X':
sum=sum-20
elif s[i]=='X':
sum=sum+10
if s[i-1]=='I':
sum=sum-2
elif s[i]=='V':
sum=sum+5
if s[i-1]=='I':
sum=sum-2
elif s[i]=='I':
sum=sum+1
return (sum)
答案 14 :(得分: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
答案 15 :(得分:0)
我知道这是一篇旧文章,但我想添加3种解决方案以将罗马数字转换为数字。
解决方案1 :(大约运行时间= 52ms)
def romanToInt(self, s: str) -> int:
roman = {'I':1, 'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':1000 }
num = 0
for i in range(len(s)):
if i!= len(s)-1 and roman[s[i]] < roman[s[i+1]]:
num += roman[s[i]]*-1
else:
num += roman[s[i]]
return num
解决方案2 :(大约运行时间= 60ms)
def romanToInt(self, s: str) -> int:
roman = {'I':1, 'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':1000 }
num = 0
s = s.replace("IV", "IIII").replace("IX", "VIIII")
s = s.replace("XL", "XXXX").replace("XC", "LXXXX")
s = s.replace("CD", "CCCC").replace("CM", "DCCCC")
for x in s:
num += roman[x]
return num
解决方案3 :(大约运行时间= 48ms)
def romanToInt(self, s: str) -> int:
roman = {'I':1, 'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':1000 }
num = 0
for i in range(len(s)-1):
if roman[s[i]] < roman[s[i+1]]:
num += roman[s[i]]*-1
continue
num += roman[s[i]]
num +=roman[s[-1]]
return num
最简单的解决方案有时似乎是最好的:)
答案 16 :(得分:-2)
试试这个:
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 将我的新生函数应用到iterable的每个元素中。在这种情况下,iterable是一个字符串,如“mclvii”。这样做我生成了一个列表,其中每个值都是他的rersepective值。请参阅lambda示例以计算平方:
>>> a = [1,2,3,4]
>>> square = lambda x: x**2
>>> l = map(square, a)
>>> l = [1,4,9,16]
因此,当您需要动态函数时它是lambda,当您想要将函数应用于列表中的所有元素时映射。
现在使用递归的示例:
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:])