-
Notifications
You must be signed in to change notification settings - Fork 0
/
romanNumeralCalculator.py
205 lines (169 loc) · 6.9 KB
/
romanNumeralCalculator.py
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
#TRENTON MORGAN
#CS 2200
#HW 1
#09/05/19
#This program performs the addition and subtraction of values represented with
#Roman numerals. It takes in the specified number of inputs (between 2 and 10
#inclusive)in the form of valid Roman numerals, then directly calculates the
#result and outputs it in the correct form.
#UTILITIES#
#---------#
#List of valid Roman numerals, sorted in order highest to lowest value.
romanNumerals = ['M','D','C','L','X','V','I']
#Dictionary of equivalences, used in expansion and compaction of values.
expansionTable = {"V" : "IIIII",
"X" : "VV",
"L" : "XXXXX",
"C" : "LL",
"D" : "CCCCC",
"M" : "DD"}
#Dictionary of subtractives, used in expansion and compaction of values.
subtractiveTable = {"IV" : "IIII",
"IX" : "VIIII",
"XL" : "XXXX",
"XC" : "LXXXX",
"CD" : "CCCC",
"CM" : "DCCCC"}
#Using regex, check that the input is a properly formatted Roman numeral.
import re #import regex module
def checkFormatting(num):
goodFormatting = False
#The expression below will match any valid Roman numeral, providing a basis
#to verify the inputs against
validExpression = "^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$"
#If the num matches the expression, the formatting is valid
goodFormatting = re.match(validExpression, num)
return goodFormatting
#Valid inputs consist of only Roman numerals, verified using the list
#romanNumerals defined above. They also must be formatted correctly, as checked
#by the checkFormatting() function. Returns the validity as a boolean value.
def checkValid(num):
validInput = False
while (not validInput):
for char in num:
if char in romanNumerals:
validInput = True
else:
validInput = False
break
#After checking that all characters in the input are Roman numerals,
#check that the number is formatted correctly
if validInput:
validInput = checkFormatting(num)
return validInput
#Directly adds two Roman numeral values and returns the result in the correct
#format.
def romanAdd(first, second):
#First we must replace any subtractives with their expansions
for subtractive in subtractiveTable.keys():
first = first.replace(subtractive, subtractiveTable[subtractive])
second = second.replace(subtractive, subtractiveTable[subtractive])
#Next, concatenate the two strings of numerals
combined = first + second
#Next, we sort the numerals in descending value order (defined in the list
#romanNumerals above)
result = ""
for numeral in romanNumerals:
for char in combined:
if char == numeral:
result += char
#Last, we compact any values that can be using the expansionTable and insert
#subtractives where needed using the subtractiveTable
for compactor in expansionTable.keys():
result = result.replace(expansionTable[compactor], compactor)
for subtractive in subtractiveTable.keys():
result = result.replace(subtractiveTable[subtractive], subtractive)
return result
#Directly subtracts second from first and returns the result.
def romanSubtract(first, second):
#First we replace subtractives with their expanded value
for subtractive in subtractiveTable.keys():
first = first.replace(subtractive, subtractiveTable[subtractive])
second = second.replace(subtractive, subtractiveTable[subtractive])
#Next, eliminate any common symbols
for char in second:
if char in first:
#Replace one instance of the symbol with an empty string
first = first.replace(char, '', 1)
#Do the same for the second input
second = second.replace(char, '', 1)
#If there are characters left over, we borrow to complete the difference
if len(second) == 0:
result = first
return result
else:
#Replace all numerals in the inputs with I
for numeral in romanNumerals[:6]:
first = first.replace(numeral, expansionTable[numeral])
second = second.replace(numeral, expansionTable[numeral])
#Eliminate common symbols
for char in second:
if char in first:
first = first.replace(char, '', 1)
second = second.replace(char, '', 1)
#The remainder of the first input is the result
result = first
#Lastly, compact the result
for compactor in expansionTable.keys():
result = result.replace(expansionTable[compactor], compactor)
for subtractive in subtractiveTable.keys():
result = result.replace(subtractiveTable[subtractive], subtractive)
return result
#DRIVER#
#------#
#The number of inputs is specified by the user (2-10 terms).
numAllowed = False
while (not numAllowed):
numInputs = input("Enter the number of terms: ")
#Ensure numInputs consists of only integer digits
if numInputs.isdigit():
numInputs = int(numInputs)
else:
numInputs = 0
#Check numInputs between 2 and 10
if numInputs >= 2 and numInputs <= 10:
numAllowed = True
else:
print("Invalid number of terms. Must be between 2 and 10 inclusive.")
terms = [] #List of terms
operators = [] #List of operators, + or - only
#Get an input for each term, as well as an operator to go between each term. All
#operations are performed on the terms in the order they are given.
for i in range(numInputs):
validInput = False
while (not validInput):
num = input("Enter the term: ")
if not checkValid(num):
print("Invalid input. Please try again.")
else:
validInput = True
terms.append(num)
#After all inputs except the last, a valid operator (+ or -) is required
if i < numInputs - 1:
validOperator = False
while (not validOperator):
operator = input("Enter operation type: ")
if operator == '+' or operator == '-':
validOperator = True
operators.append(operator)
else:
print("Invalid operator. Please try again.")
#With valid inputs, perform the operations designated by their list, going
#first to last.
print("Performing calculation...")
numTerms = len(terms)
for i in range(numTerms - 1):
#Get first two terms and an operator
first = terms.pop(0)
second = terms.pop(0)
operator = operators.pop(0)
#Add if +, subtract if -
if operator == '+':
result = romanAdd(first, second)
else:
result = romanSubtract(first, second)
#Re-insert the result in the list so it will be used in the next operation
terms.insert(0, result)
finalResult = terms[0]
print("Final result:")
print(finalResult)