programming

모 회사 코딩 시험 - 로마숫자 사칙연산 계산기 python 풀이 (1)


by Kitle · 2020. 06. 30.



우연히 알게된 모 회사 코딩 시험문제인 로마숫자 사칙연산 계산기 입니다. 문제는 공개되어 있습니다.

절대 해당 코드로 제출하지 마시길 바라며, 아래는 정답도 아니며 복붙하여 내는 경우 책임을 지지 않습니다. 스터디/학습용으로만 사용하시길 바랍니다.

문제

로마 숫자는 고대 로마에서 사용된 기수법입니다.
기본적으로 다음 5가지를 조합하여 로마 숫자를 읽고 쓸 수 있습니다.
I = 1
II = 2
III = 3
V = 5
X = 10

4, 6, 7, 8, 9는 규칙을 이용하여 표시합니다.
V 또는 X를 기준으로 왼쪽에 I가 오면 빼고 오른쪽에 I, II, III이 오면 더해서 표시합니다.

위와 같은 규칙으로 1 ~ 10까지 표시하면 다음과 같습니다.

로마 숫자

아라비아 숫자

I

1

II

2

III

3

IV

4

V

5

VI

6

VII

7

VIII

8

IX

9

X

10


조건

  • 사칙연산이 가능한 계산기를 작성해 주세요.
  • 입력값과 결과값의 범위는 I ~ XXIX (1 ~ 39) 입니다.
  • 결과값이 0이하 이거나 39(XXXIX)보다 큰 경우 “범위를 벗어났습니다.”라고 표시해 주세요.
  • 작은 수에서 큰 수를 빼는 경우 “작은 수에서 큰수를 뺄 수 없습니다.”라고 표시해 주세요.
  • 작은 수를 큰 수로 나누는 경우 “작은 수를 큰 수로 나눌 수 없습니다.”라고 표시해 주세요.
  • 나누기(/)의 결과 값은 몫과 나머지로 표시해 주세요.
  • 입력은 파일이나 콘솔에서 받아도 되고 프로그램 내부에 하드코딩해도 됩니다.

예시

예 1)

입력

I + I

출력

II

 
예 2)

입력

XX – IV

출력

XVI

 
예 3)

입력

III * VI

출력

XVIII

 
예 4)

입력

X / III

출력

III, 나머지 I

 
예 5)

입력

III / X

출력

작은 수를 수로 나눌 없습니다.

 
예 6)

입력

X – XXX

출력

작은 수에서 수를 없습니다.

 
예 7)

입력

XX + XX

출력

범위를 벗어났습니다.





def roman_to_arabic(roman_number):
conversion_string = {
'I': 1,
'II': 2,
'III': 3,
'V': 5,
'X': 10,
}

if roman_number in conversion_string:
return conversion_string[roman_number]
else:
result = 0
before_string = None
for now_string in reversed(roman_number):
# I 가 먼저 나오면 더하고, (최대 3개)
# 원문을 리버스(IV -> VI)하여 X, V 가 먼저오고 I 가 뒤에 나오면 뺀다. 나머지 규칙은 다 더하기.
if before_string in ('V', 'X') and now_string == 'I':
result -= conversion_string[now_string]
else:
result += conversion_string[now_string]
before_string = now_string
return result



def arabic_to_roman(arabic_number):
conversion_string = {
1: 'I',
2: 'II',
3: 'III',
5: 'V',
10: 'X',
}

if arabic_number in conversion_string:
return conversion_string[arabic_number]
else:
result = ''
temp_number = arabic_number
while temp_number > 10:
result += 'X'
temp_number -= 10

if temp_number in conversion_string:
result += conversion_string[temp_number]
else:
if temp_number > 8:
result += 'IX'
else:
if temp_number < 5:
result += 'IV'
if temp_number > 5:
result += 'VI'
if temp_number > 6:
result += 'I'
if temp_number > 7:
result += 'I'

return result


def data_cleaning(user_input_string):
user_input_string = user_input_string.split(" ")
# if "" in user_input_string:
# user_input_string.remove("")
return user_input_string


def split_string(temp_input_value, temp_op, temp_var):
for temp_item in temp_input_value:
if temp_item in ('+', '-', '*', '/'):
temp_op.append(temp_item)
else:
temp_var.append(temp_item)
return temp_op, temp_var


def calculator(temp_op, temp_var1, temp_var2):
result_one = None
result_two = None
if (not 0 < temp_var1 < 40) or (not 0 < temp_var2 < 40):
print('범위를 벗어났습니다.')
return result_one, result_two

if temp_op == '+':
result_one = temp_var1 + temp_var2
elif temp_op == '-':
if temp_var1 < temp_var2:
print('작은 수에서 큰 수를 뺄 수 없습니다.')
return result_one, result_two
else:
result_one = temp_var1 - temp_var2
elif temp_op == '*':
result_one = temp_var1 * temp_var2
elif temp_op == '/':
if temp_var1 < temp_var2:
print('작은 수를 큰 수로 나눌 수 없습니다.')
return result_one, result_two
else:
result_one = temp_var1 // temp_var2
result_two = temp_var1 % temp_var2


if not 0 < result_one < 40 :
print('범위를 벗어났습니다.')
return None, None
else:
return result_one, result_two


def result_printer(temp_var1, temp_var2):
if temp_var1 is not None and temp_var2 is None:
print(arabic_to_roman(temp_var1))
elif temp_var1 is not None and temp_var2 is not None:
if temp_var2 == 0:
print('몫', arabic_to_roman(temp_var1) + ',', '나머지', '?')
else:
print('몫',arabic_to_roman(temp_var1)+',','나머지',arabic_to_roman(temp_var2))




if __name__ == "__main__":
temp_op = []
temp_var = []

user_input = 'XXIX / XX'
cleaned_data = data_cleaning(user_input)
temp_op, temp_var = split_string(cleaned_data, temp_op, temp_var)
temp_var1 = roman_to_arabic(temp_var[0])
temp_var2 = roman_to_arabic(temp_var[1])
result_var1, result_var2 = calculator(temp_op[0], temp_var1, temp_var2)
result_printer(result_var1, result_var2)

  


문제풀이

*로마숫자를 아라비아 숫자로 1:1로 매핑해서 변환하면 굳이 이렇게 안해도 될것같은데, 일단은 문제에 충실하게 해야 하므로 필요한 것들은 다음과 같다.

1. 로마숫자 -> 아라비아 숫자 변환 함수

 사용자 입력 I X V 등을  1, 10, 5 로 변환해야한다. 그래야 사칙연산이 가능하다.

  기본규칙인 I, II, III, V, X 가 아닌경우 문자를 하나씩 분리하여 더하거나 빼는 방식으로 계산한다.

  여기서는 계산하기 쉽게 IV (4) 같은 경우는 문자 순서를 리버스 하여 VI 로 만들어 I가 먼저 나오면 더하고 X, V가 먼저나오고 뒤에 I가 나오면 뺀다. 즉 IV -> 리버스 VI -> V먼저나오고 I  이니 V - I = 4로 판단한다. 

2. 아라비아 -> 로마숫자 변환함수

 사칙연한 결과를 다시 로마숫자로 표시해줘야 하므로 해당 함수가 필요하다.

 아라비아 숫자는 몫과 나머지를 계산하여 조합한다.

3. 데이터 클리닝 함수

 사용자 입력에 공백을 제거한다. 문자열 처리를 깔끔하게 하기위해 보통 한다.

4. 문자열 나누기 함수

  X + I  의 경우 어떤게 연산자고 어떤게 피연산자인지 알아야 한다. 따라서 규칙에 따라 나눈다.

5. 계산기 함수

 실제 계산기이나 해당 퀴즈에서는 범위제한과 각종 예외처리가  있으므로 범위 제한에 대한 예외처리를 해준다. 

6. 결과 출력 함수

 특별하게 나누기의 경우 몫과 나머지가 있다. 나누기 연산을 할때만 나머지가 생기므로 이때만 특별하게 처리한다.

7. 주의사항

로마 숫자는 해당 퀴즈 내에서는 0에 대한 처리 규칙이 없다. 그러나 나누기 연산시 나머지가 0이 발생한다. 우선은 이 경우를 ? 로 예외처리 하였다.

그외에도 문제에 포함되지 않은 예외사항들을 잘 찾아야 한다.