1.说明
1.题目应在本周5中午十二点之前提交
2.题目测试考察包含对题意的理解以及代码整洁度和简易度,测试的数据会变动
3.最好有相关的单元测试,如果能达到100%测试覆盖率且能正确的使用mock对象最好.如果时间不够或者不熟悉测试方法否,这一部分可忽略.功能完整性是首要考察.
4.建议使用github或其它git托管工具托管一份,提交时直接给出链接.合理的commit,如果符合小步更改提交的准则会有加分.
2.Merchant’s Guide To The Galaxy
Python
Description You decided to give up on earth after the latest financial collapse left 99.99% of the earth's population with 0.01% of the wealth. Luckily, with the scant sum of money that is left in your account, you are able to afford to rent a spaceship, leave earth, and fly all over the galaxy to sell common metals and dirt (which apparently is worth a lot). Buying and selling over the galaxy requires you to convert numbers and units, and you decided to write a program to help you. The numbers used for intergalactic transactions follows similar convention to the roman numerals and you have painstakingly collected the appropriate translation between them. Numbers are formed by combining symbols together and adding the values. For example, MMVI is 1000 1000 5 1 = 2006. Generally, symbols are placed in order of value, starting with the largest values. When smaller values precede larger values, the smaller values are subtracted from the larger values, and the result is added to the total. For example MCMXLIV = 1000 (1000 − 100) (50 − 10) (5 − 1) = 1944. The symbols "I", "X", "C", and "M" can be repeated three times in succession, but no more. (They may appear four times if the third and fourth are separated by a smaller value, such as XXXIX.) "D", "L", and "V" can never be repeated. "I" can be subtracted from "V" and "X" only. "X" can be subtracted from "L" and "C" only. "C" can be subtracted from "D" and "M" only. "V", "L", and "D" can never be subtracted. Only one small-value symbol may be subtracted from any large-value symbol. A number written in Arabic numerals can be broken into digits. For example, 1903 is composed of 1, 9, 0, and 3. To write the Roman numeral, each of the non-zero digits should be treated separately. In the above example, 1,000 = M, 900 = CM, and 3 = III. Therefore, 1903 = MCMIII. Input to your program consists of lines of text detailing your notes on the conversion between intergalactic units and roman numerals. You are expected to handle invalid queries appropriately. INPUT: glob is I prok is V pish is X tegj is L glob glob Silver is 34 Credits glob prok Gold is 57800 Credits pish pish Iron is 3910 Credits how much is pish tegj glob glob ? how many Credits is glob prok Silver ? how many Credits is glob prok Gold ? how many Credits is glob prok Iron ? OUTPUT pish tegj glob glob is 42 glob prok Silver is 68 Credits glob prok Gold is 57800 Credits glob prok Iron is 782 Credits
1234567891011121314151617181920212223242526272829303132 | Description You decided to give up on earth after the latest financial collapse left 99.99% of the earth's population with 0.01% of the wealth. Luckily, with the scant sum of money that is left in your account, you are able to afford to rent a spaceship, leave earth, and fly all over the galaxy to sell common metals and dirt (which apparently is worth a lot). Buying and selling over the galaxy requires you to convert numbers and units, and you decided to write a program to help you. The numbers used for intergalactic transactions follows similar convention to the roman numerals and you have painstakingly collected the appropriate translation between them. Numbers are formed by combining symbols together and adding the values. For example, MMVI is 1000 1000 5 1 = 2006. Generally, symbols are placed in order of value, starting with the largest values. When smaller values precede larger values, the smaller values are subtracted from the larger values, and the result is added to the total. For example MCMXLIV = 1000 (1000 − 100) (50 − 10) (5 − 1) = 1944. The symbols "I", "X", "C", and "M" can be repeated three times in succession, but no more. (They may appear four times if the third and fourth are separated by a smaller value, such as XXXIX.) "D", "L", and "V" can never be repeated. "I" can be subtracted from "V" and "X" only. "X" can be subtracted from "L" and "C" only. "C" can be subtracted from "D" and "M" only. "V", "L", and "D" can never be subtracted. Only one small-value symbol may be subtracted from any large-value symbol. A number written in Arabic numerals can be broken into digits. For example, 1903 is composed of 1, 9, 0, and 3. To write the Roman numeral, each of the non-zero digits should be treated separately. In the above example, 1,000 = M, 900 = CM, and 3 = III. Therefore, 1903 = MCMIII. Input to your program consists of lines of text detailing your notes on the conversion between intergalactic units and roman numerals. You are expected to handle invalid queries appropriately. INPUT:glob is Iprok is Vpish is Xtegj is Lglob glob Silver is 34 Creditsglob prok Gold is 57800 Creditspish pish Iron is 3910 Creditshow much is pish tegj glob glob ?how many Credits is glob prok Silver ?how many Credits is glob prok Gold ?how many Credits is glob prok Iron ? OUTPUTpish tegj glob glob is 42glob prok Silver is 68 Creditsglob prok Gold is 57800 Creditsglob prok Iron is 782 Credits |
---|
3.题意解析
3.1 题目说明
省略前言就是说,帮助商人去进行罗马数字和阿拉伯数字的转换
罗马字母有: I,V,X,L,C,D,M
规则有:
0.如果小数字的出现在大数字的前面则表示减.例如MCMXLIV = 1000 (1000 − 100) (50 − 10) (5 − 1) = 1944.
1. I:可以表示十进制数字1,V:可以表示十进制数字5,X:可以表示十进制数字10,L:可以表示十进制数字50,C:可以表示十进制数字100,D:可以表示十进制数字500,M:可以表示十进制数字1000;
2.I, X, C, and M可以重复出现最多3次;(这个不好处理一点)
3.一般是从后往前排列:即MDCLXVI的顺序,当然也允许相邻的两个倒序,但是需要符合以下规则:
I :只能组合IV ,IX
X:只能组合XL,XC
C:只能组合CD,CM
V,L,D不能倒序
3.2 测试数据解析
Python
glob is I prok is V pish is X tegj is L glob glob Silver is 34 Credits glob prok Gold is 57800 Credits pish pish Iron is 3910 Credits how much is pish tegj glob glob ? how many Credits is glob prok Silver ? how many Credits is glob prok Gold ? how many Credits is glob prok Iron ?
1234567891011 | glob is Iprok is Vpish is Xtegj is Lglob glob Silver is 34 Creditsglob prok Gold is 57800 Creditspish pish Iron is 3910 Creditshow much is pish tegj glob glob ?how many Credits is glob prok Silver ?how many Credits is glob prok Gold ?how many Credits is glob prok Iron ? |
---|
Python
OUTPUT pish tegj glob glob is 42 glob prok Silver is 68 Credits glob prok Gold is 57800 Credits glob prok Iron is 782 Credits
12345 | OUTPUTpish tegj glob glob is 42glob prok Silver is 68 Creditsglob prok Gold is 57800 Creditsglob prok Iron is 782 Credits |
---|
首先是若干行.代表某些单词对应的罗马字母.
然后是若干行,这部分出现的单词需要用前面的进行翻译.多少的(银金铁)币是多少的货币.这里则是给出了交易币以及交易单位的价格比.
再若干行,这部分会出现两种问法,
问how much则是直接在is后面给出一串字符串,照之前进行罗马数转化成阿拉伯数.
问how many则是计算多少的(银金铁)币是多少的货币.
例如:
Python
glob glob Silver is 34 Credits #说明II(2)个银币是34元(基础货币单位)则可以得出一个银币是17元
12 | glob glob Silver is 34 Credits#说明II(2)个银币是34元(基础货币单位)则可以得出一个银币是17元 |
---|
Python
how many Credits is glob prok Silver ? #问.IV(4)个银币是多少元,可以得出34/2*4=68,符合输出结果
12 | how many Credits is glob prok Silver ?#问.IV(4)个银币是多少元,可以得出34/2*4=68,符合输出结果 |
---|
别的就不再解析.
3.2 难点分析:
首先必然有一个基础的罗马转数字.之后是字典的构建,将单词与罗马字母对应起来.
进行字符串解析.因为不限制每一行的长度,所以复杂起来,只能用将模块裂开进行解析.其中每一个部分是没有条数限制的,所以只能通过读取一行再分析出这一行是干嘛的.
第一部分的是字典对应过去,所以可以判断最后一个字母是不是在罗马字母中,而且是大写.
第二部分则是以credits结尾
第三部分则是问号结尾以how mach/many区别
4.模块化
4.1 Roma 数字转阿拉伯数字
解析在代码中.建议将内部的#test的注释取消,来看看逐步的结果就明白了
Python
#coding:utf-8 import re #正则表达式 def getRomanNum(RomanStr): ''' 输入罗马数字字符串,输出转换后的阿拉伯字符串 逻辑说明:原本是使用所有规则一个个if来判断处理的,但是这样的代码非常垃圾,学习后改进. 使用正则的类似思想,对输入串判断romanpattern中规则出现的情况, 例如以MXCVI为例,则在pattern的结果是:^M{1}C{0}XCX{0}VI{1} 1000 90 6这里就可以按照千百十分位来分别判断处理 其中retnum则是存放转化后的阿拉伯数字,用于返回. ''' #正则表达式进行匹配,判断输入是否合法 if re.search('^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$',RomanStr)!=None: NumDic = {"pattern":"","retNum":0}#值记录区 # 如测试数为 XCVI 则最后retNum 96 pattern ^M{0}C{0}XCX{0}VI{1} 展示出现数次 RomanPattern = { "0":('','','','M'), # 1000 "1":('CM','CD','D','C',100), #900 400 500 100 "2":('XC','XL','L','X',10), #90 40 50 10 "3":('IX','IV','V','I',1)#9 4 5 1 } i = 3 NumItems = sorted(RomanPattern.items())#对字典先排序返回元组 for RomanItem in NumItems: if RomanItem[0] != '0':#先统计千内的 patstr = NumDic["pattern"].join(['',RomanItem[1][0]]) #print "R " RomanItem[1][0] if re.search(patstr,RomanStr) != None:#先判断Romanstr中是否存在parstr NumDic["retNum"] = 9*RomanItem[1][4] # =90 NumDic["pattern"] = patstr #存放正则信息 else: patstr = NumDic["pattern"].join(['',RomanItem[1][1]]) #print patstr if re.search(patstr,RomanStr) != None: NumDic["retNum"] = 4*RomanItem[1][4] # =40 NumDic["pattern"] = patstr else: patstr = NumDic["pattern"].join(['',RomanItem[1][2]]) if re.search(patstr,RomanStr) != None: NumDic["retNum"] = 5*RomanItem[1][4] # = 50 NumDic["pattern"] = patstr # test #print "retNum " str(NumDic["retNum"]) , #print "pattern " NumDic["pattern"] if NumDic["pattern"] == '': NumDic["pattern"] = '^'#标志 tempstr = '' sum = 0 for k in range(0,4):#处理连续出现几次 pstr = RomanItem[1][3].join(['','{']).join(['',str(k)]).join(['','}']) patstr = NumDic["pattern"].join(['',pstr]) if re.search(patstr,RomanStr) != None: sum = k*(10**i) tempstr = patstr if tempstr <> '':#不等于即依旧为原始值 NumDic["pattern"] = tempstr else: NumDic["pattern"] = patstr NumDic['retNum'] = sum i -= 1 return NumDic['retNum'] #return NumDic['pattern'] else: print 'String is not a valid Roman numerals' print getRomanNum('MXCVI')
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869 | #coding:utf-8import re #正则表达式 def getRomanNum(RomanStr): ''' 输入罗马数字字符串,输出转换后的阿拉伯字符串 逻辑说明:原本是使用所有规则一个个if来判断处理的,但是这样的代码非常垃圾,学习后改进. 使用正则的类似思想,对输入串判断romanpattern中规则出现的情况, 例如以MXCVI为例,则在pattern的结果是:^M{1}C{0}XCX{0}VI{1} 1000 90 6这里就可以按照千百十分位来分别判断处理 其中retnum则是存放转化后的阿拉伯数字,用于返回. ''' #正则表达式进行匹配,判断输入是否合法 if re.search('^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$',RomanStr)!=None: NumDic = {"pattern":"","retNum":0}#值记录区 # 如测试数为 XCVI 则最后retNum 96 pattern ^M{0}C{0}XCX{0}VI{1} 展示出现数次 RomanPattern = { "0":('','','','M'), # 1000 "1":('CM','CD','D','C',100), #900 400 500 100 "2":('XC','XL','L','X',10), #90 40 50 10 "3":('IX','IV','V','I',1)#9 4 5 1 } i = 3 NumItems = sorted(RomanPattern.items())#对字典先排序返回元组 for RomanItem in NumItems: if RomanItem[0] != '0':#先统计千内的 patstr = NumDic["pattern"].join(['',RomanItem[1][0]]) #print "R " RomanItem[1][0] if re.search(patstr,RomanStr) != None:#先判断Romanstr中是否存在parstr NumDic["retNum"] = 9*RomanItem[1][4] # =90 NumDic["pattern"] = patstr #存放正则信息 else: patstr = NumDic["pattern"].join(['',RomanItem[1][1]]) #print patstr if re.search(patstr,RomanStr) != None: NumDic["retNum"] = 4*RomanItem[1][4] # =40 NumDic["pattern"] = patstr else: patstr = NumDic["pattern"].join(['',RomanItem[1][2]]) if re.search(patstr,RomanStr) != None: NumDic["retNum"] = 5*RomanItem[1][4] # = 50 NumDic["pattern"] = patstr # test #print "retNum " str(NumDic["retNum"]) , #print "pattern " NumDic["pattern"] if NumDic["pattern"] == '': NumDic["pattern"] = '^'#标志 tempstr = '' sum = 0 for k in range(0,4):#处理连续出现几次 pstr = RomanItem[1][3].join(['','{']).join(['',str(k)]).join(['','}']) patstr = NumDic["pattern"].join(['',pstr]) if re.search(patstr,RomanStr) != None: sum = k*(10**i) tempstr = patstr if tempstr <> '':#不等于即依旧为原始值 NumDic["pattern"] = tempstr else: NumDic["pattern"] = patstr NumDic['retNum'] = sum i -= 1 return NumDic['retNum'] #return NumDic['pattern'] else: print 'String is not a valid Roman numerals' print getRomanNum('MXCVI') |
---|
4.2 输入的字符串解析
这部分就简单多了,说明在代码中
Python
#coding:utf-8 from Roma_to_num_test import getRomanNum Romanarray=['I','V','X','L','C','D','M'] word_dic = {}#以字典来对应单词和罗马数字 coin_dic = {}#以字典来对应货币和价值 def str_Resolve(input_line): ''' 输入每一行的字符串类型信息:如题目中的测试数据.返回分类机处理后的信息. 程序代码说明: 结构很明显,按照末尾字符是否在Romanarray中,判断是否是第一类定义单词输入 否则判断是否以小写s结束,判断是否是作为第二类金币银币类型输入 否则判断末尾是否是?号为第三类输入.进行按照空格划分之后判断第二个单词 按照many和mach进行分别返回处理 ''' if input_line[-1] in Romanarray: input_line_array = input_line.split(' ')#以空格截取 word_dic[input_line_array[0]] = input_line_array[2]#取第一个和最后一个元素 return #print 'word_dic:',word_dic: elif input_line[-1] == 's':#以小写s做为金币银币那些测试数据的识别符号 input_line_array = input_line.split(' ')#以空格截取 temp_str = '' for i in range(len(input_line_array)-4): temp_str = word_dic[input_line_array[i]] temp_num = getRomanNum(temp_str) #print "input_line_array[-4]",input_line_array[-4] coin_dic[input_line_array[-4]] = int(input_line_array[-2])/int(temp_num) return #print 'coin_dic:',coin_dic elif input_line[-1] == '?': #以?为标志,判断是否是第三四类输入 input_line_array = input_line.split(' ') #print "input_line_array:",input_line_array if input_line_array[1] == 'much': temp_str1 = '' temp_str3 = '' for i in range(3,len(input_line_array)-1):#抽取第四个到最后一个数组元素 temp_str3 = input_line_array[i] ' ' temp_str1 = word_dic[input_line_array[i]] return temp_str3 "is " str(getRomanNum(temp_str1))#转化成数字并且输出 elif input_line_array[1] == 'many':#处理many temp_str2 = '' temp_str4 = '' for i in range(4,len(input_line_array)-2):#取第5个到倒数第三个之间 temp_str4 = input_line_array[i] ' ' temp_str2 = word_dic[input_line_array[i]]#转化为字符进行roma查询 return temp_str4 input_line_array[-2] ' is ' str(coin_dic[input_line_array[-2]]*getRomanNum(temp_str2) ) ' Credits'#输出数量*单位价值
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859 | #coding:utf-8from Roma_to_num_test import getRomanNum Romanarray=['I','V','X','L','C','D','M'] word_dic = {}#以字典来对应单词和罗马数字coin_dic = {}#以字典来对应货币和价值 def str_Resolve(input_line): ''' 输入每一行的字符串类型信息:如题目中的测试数据.返回分类机处理后的信息. 程序代码说明: 结构很明显,按照末尾字符是否在Romanarray中,判断是否是第一类定义单词输入 否则判断是否以小写s结束,判断是否是作为第二类金币银币类型输入 否则判断末尾是否是?号为第三类输入.进行按照空格划分之后判断第二个单词 按照many和mach进行分别返回处理 ''' if input_line[-1] in Romanarray: input_line_array = input_line.split(' ')#以空格截取 word_dic[input_line_array[0]] = input_line_array[2]#取第一个和最后一个元素 return #print 'word_dic:',word_dic: elif input_line[-1] == 's':#以小写s做为金币银币那些测试数据的识别符号 input_line_array = input_line.split(' ')#以空格截取 temp_str = '' for i in range(len(input_line_array)-4): temp_str = word_dic[input_line_array[i]] temp_num = getRomanNum(temp_str) #print "input_line_array[-4]",input_line_array[-4] coin_dic[input_line_array[-4]] = int(input_line_array[-2])/int(temp_num) return #print 'coin_dic:',coin_dic elif input_line[-1] == '?': #以?为标志,判断是否是第三四类输入 input_line_array = input_line.split(' ') #print "input_line_array:",input_line_array if input_line_array[1] == 'much': temp_str1 = '' temp_str3 = '' for i in range(3,len(input_line_array)-1):#抽取第四个到最后一个数组元素 temp_str3 = input_line_array[i] ' ' temp_str1 = word_dic[input_line_array[i]] return temp_str3 "is " str(getRomanNum(temp_str1))#转化成数字并且输出 elif input_line_array[1] == 'many':#处理many temp_str2 = '' temp_str4 = '' for i in range(4,len(input_line_array)-2):#取第5个到倒数第三个之间 temp_str4 = input_line_array[i] ' ' temp_str2 = word_dic[input_line_array[i]]#转化为字符进行roma查询 return temp_str4 input_line_array[-2] ' is ' str(coin_dic[input_line_array[-2]]*getRomanNum(temp_str2) ) ' Credits'#输出数量*单位价值 |
---|
4.3 使用文件读取测试数据的main.py
Python
#coding:utf-8 from str_Resolve import * import fileinput ''' 测试/使用说明: 请将新的测试数据,使用文本的形式存放在test-data文件夹下,同时修改文件读取的路径 ''' for line in fileinput.input("../test-data/input_2.txt"): str_line=line[:-1]#去除行结尾的换行符号,未知为何会多出一个换行 ,根据环境不同可能有差别 #print str_line try: str_return = str_Resolve(str_line) if str_return: print str_return except: print "I have no idea what you are talking about"
1234567891011121314151617 | #coding:utf-8from str_Resolve import *import fileinput'''测试/使用说明:请将新的测试数据,使用文本的形式存放在test-data文件夹下,同时修改文件读取的路径''' for line in fileinput.input("../test-data/input_2.txt"): str_line=line[:-1]#去除行结尾的换行符号,未知为何会多出一个换行 ,根据环境不同可能有差别 #print str_line try: str_return = str_Resolve(str_line) if str_return: print str_return except: print "I have no idea what you are talking about" |
---|
数据放在github上,见文章头部
在1,2,3组测试数据下正确得出了结果
但是第一组感觉是题目错误 不是782而是780.手算也是这个答案.