在python中将罗马数字转换为整数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19308177/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Converting Roman Numerals to integers in python
提问by Jake
This is now my current code after what user2486 said.
在 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()
I am getting this error with while ns: UnboundLocalError: local variable 'ns' referenced before assignment
while ns: UnboundLocalError: local variable 'ns' referenced before assignment 我收到这个错误
采纳答案by user2864740
Consider this additional pseudo-code and hints (some of it is valid Python, some isn't, but there be notes).
考虑这个额外的伪代码和提示(其中一些是有效的 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:]
回答by Peacemaker636
Okay, there are a lot of things wrong with what you currently have.
好的,您目前拥有的东西有很多问题。
First, the reason you are getting a bunch of 0's is because you are never exiting your while string != "":
loop, and it isn't ever adding integers to the total. So total
remains zero, and keeps getting printed. I've commented the code you posted to help you understand what is going on.
首先,您得到一堆 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 has some good comments in their posted solution, look over that to see some of the things you were doing wrong.
user2864740 在他们发布的解决方案中有一些很好的评论,查看一下,看看你做错了什么。
Here is Python (2.7 unfortunately) code that does what your given pseudocode says.
这是 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()
Please note that the pseudocode you posted is NOT correct. Note what it will do for the input 'IIV'
. It will subtract 1 from 1, then add 5. But what it should do is subtract 2 from 5.
请注意,您发布的伪代码不正确。请注意它将对 input 做什么'IIV'
。它会从 1 中减去 1,然后加上 5。但是它应该做的是从 5 中减去 2。
回答by Lucas Ribeiro
try this:
尝试这个:
def translate(string):
values = {"i":1, "v":5, "x":10, "l":50, "c":100, "m":1000}
return sum(map(lambda x: values[x], string))
The lambda stands for a one-line function. That's why they are called anonymous functions. You don't have to define them outide using def and all that formality.
lambda 代表单行函数。这就是为什么它们被称为匿名函数。您不必使用 def 和所有这些形式来定义它们。
You can type something like this on the shell:
你可以在 shell 上输入这样的东西:
f = lambda x: x + 3 f(3) 6 or f = lambda x,y: x + y f("foo", "bar") 'foobar'
f = lambda x: x + 3 f(3) 6 或 f = lambda x,y: x + y f("foo", "bar") 'foobar'
Im using mapto apply my new-born function into every element of a iterable. In this case, the iterable is one string like "mclvii". Doing it i generated a list where each value its his rersepective value. See a lambda example to calculate squares:
我使用map将我的新功能应用于可迭代的每个元素。在这种情况下,迭代是一个字符串,如“mclvii”。这样做我生成了一个列表,其中每个值都是他的相对值。请参阅 lambda 示例来计算平方:
>>> a = [1,2,3,4]
>>> square = lambda x: x**2
>>> l = map(square, a)
>>> l = [1,4,9,16]
So, it's lambda when you need a function on the fly, and map when you want to apply a function to all elements in a list.
所以,当你需要一个动态的函数时,它是 lambda,当你想将一个函数应用于列表中的所有元素时,它是 map。
Now a example using recursion:
现在是一个使用递归的例子:
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:])
回答by pepr
There is a very detailed description of the development of the Roman numeral converters in the Dive Into Python 3by Mark Pilgrim. See the 5.3. Case Study: Roman Numeralsthat introduces the problem and details.
Mark Pilgrim在Dive Into Python 3中对罗马数字转换器的开发进行了非常详细的描述。见5.3。案例研究:介绍问题和细节的罗马数字。
But that is not all. See the Chapter 9. Unit Testingwhere the analysis and the implementation of Roman numeral converters continues, including interesting optimization and exception throwing -- the (unit) test driven development.
但这还不是全部。请参阅第 9 章单元测试,其中继续分析和实现罗马数字转换器,包括有趣的优化和异常抛出——(单元)测试驱动开发。
It is directly related to the enginefree's reference to the code in the first comment below the question (the code was written by Mark Pilgrim).
它与 enginefree 对问题下方第一条评论中的代码的引用直接相关(代码由 Mark Pilgrim 编写)。
回答by Brōtsyorfuzthrāx
No need to reinvent the wheel (unless you want to). Python comes with a converter:
无需重新发明轮子(除非您愿意)。Python 自带一个转换器:
import roman;
n=roman.fromRoman("X"); #n becomes 10
If you need it for numbers 5000 and above, you'll need to write a new function, though, and maybe make your own font to represent the lines over the roman numerals. (It will only work with some numbers, at that. Stopping at 4999 is a really good idea.)
但是,如果您需要为 5000 及以上的数字使用它,则需要编写一个新函数,并且可能制作自己的字体来表示罗马数字上的线条。(它只适用于一些数字。在 4999 停止是一个非常好的主意。)
To convert to roman numerals, use roman.toRoman(myInt)
.
要转换为罗马数字,请使用roman.toRoman(myInt)
.
Someone else actually linked to the same source code the roman module uses in one of the comments above, but I don't believe they mentioned that it actually comes with Python.
其他人实际上链接到 roman 模块在上述评论之一中使用的相同源代码,但我不相信他们提到它实际上与 Python 一起提供。
EDIT: Note that on some systems (Windows, I think) you can't just type import roman
from the default installation. However, the source code still works on Windows, and it's included with the Python 3.4.1 source code download (probably earlier ones, too) at this location /Python-3.4.1/Doc/tools/roman.py
编辑:请注意,在某些系统(我认为是 Windows)上,您不能仅从import roman
默认安装中键入。但是,源代码仍然适用于 Windows,它包含在此位置的 Python 3.4.1 源代码下载(也可能是更早的源代码)中/Python-3.4.1/Doc/tools/roman.py
回答by Valentin Shergin
Here is my solution:
这是我的解决方案:
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
回答by Vicks
Here's something i came up with using dictionary. It should be v.simple. Tell me what you think. I must say it does not handle the spoof roman numerals written in the form of MIM (instead of MCMXCIX for 1999). This is only for valid roman numerals.
这是我使用字典想出的东西。它应该是简单的。告诉我你的想法。我必须说它不处理以 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
回答by Vishav Vikram Kapoor
You can use this code:
您可以使用此代码:
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
回答by runitfirst
what about This piece of Code
这段代码怎么样
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
回答by Gatis Seja
Work from right to left of the roman numeral to add or subtract values. Easy.
从罗马数字的右到左工作以添加或减去值。简单。
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