cote) 암아존 배조스씨를 위한 계좌이체 한글 음성 안내
암아존 배조스씨를 위한 계좌이체 한글 음성 안내
우리말을 쓰는 평범한 사람이라면 1억원 1조원을 일억원, 일조원이라 하지 억원, 조원이라 읽지는 않습니다. 반면에 1만원, 1천원, 1백원의 경우는 일만원, 일천원, 일백원이라 하지 않고 만원, 천원, 백원, 십원이라 읽습니다. 또한 ‘80,270원’처럼 금액의 표기는 천단위로 콤마를 찍지만 실제로 읽을 때는 ‘팔만 이백칠십원’처럼 만단위로 분리하여 읽습니다.
“배조스님의 계좌에서 사이냅소프트님의 계좌로 일조 사천 일백 팔십 오억 원을 이체합니다. 동의하시면 1번을…”
계좌이체 음성안내의 부자연스러운 금액 표현과 띄어읽기가 거슬렸던 암아존 배조스씨를 위해 이체금액을 한글로 자연스럽게 읽을 수 있는 프로그램을 작성해서 보내주세요 작성하세요. 프로그래밍 언어는 가장 자신있는 것을 사용하세요.
입력
암아존 배조스님의 은행 이체한도는 100조원으로 설정돼 있으므로 입력 금액의 범위는 1원에서 100조원까지입니다.
모든 금액은 천단위 구분자인 콤마가 표시돼있고 금액단위인 원으로 끝납니다.
예로 아래와 같은 입력이 가능하고 입력은 별도 파일에서 읽어와도 되고, 소스코드안에 포함시켜도 됩니다.
물론 UI를 만들어 사용자로부터 직접 입력 받아도 좋습니다.
1원
80,270원
111,111원
1,234,567,890원
100,000,000,000,000원
출력
각각의 입력에 대하여 만단위로 띄어쓰기 구분된 자연스러운 한글읽기를 출력합니다.
위 예의 출력은 다음과 같습니다.
일원
팔만 이백칠십원
십일만 천백십일원
십이억 삼천사백오십육만 칠천팔백구십원
백조원
출처) 사이냅소프트 채용퀴즈
아래 정답란에는..
아래 코드로 접힌 영역의 모든 이체금액을 각각 한글로 읽었을 때의 어절 개수와 한글 개수를 곱한 값을 모두 더하여 제출하세요. 예를 들어, ‘10원’은 ‘십원’으로 읽고 1어절 2한글이므로 1x2 = 2이고, ‘7,000,020,000원’은 ‘칠십억 이만원’으로 읽고 2어절 6한글이므로 2x6 = 12입니다. 따라서 이 두 금액만 이체한다면 그 합은 14입니다.
요구 입력문
1원
4원
8원
9원
10원
17원
79원
80원
95원
205원
809원
851원
878원
2,000원
2,800원
7,008원
8,174원
9,718원
45,150원
50,000원
69,700원
382,915원
431,409원
921,500원
5,003,052원
5,039,670원
6,835,623원
8,000,000원
10,000,003원
35,100,000원
39,997,777원
90,021,015원
93,275,690원
403,197,000원
459,176,461원
730,080,000원
999,999,000원
6,887,000,000원
7,000,020,000원
7,700,000,500원
7,848,761,270원
38,048,620,625원
57,000,000,000원
74,778,562,249원
97,417,165,814원
101,000,120,000원
343,000,000,000원
458,807,907,862원
872,818,015,000원
6,278,000,015,000원
7,991,000,844,000원
9,000,400,000,675원
22,018,914,675,100원
78,196,000,000,000원
85,000,904,224,858원
95,000,000,404,918원
풀이 코드
풀이 과정
단위 | ||||
---|---|---|---|---|
조 | 천 | 백(15) | 십 | 조(13) |
억 | 천(12) | 백 | 십 | 억(9) |
만 | 천(8) | 백 | 십 | 만(5) |
기본 | 천(4) | 백 | 십 | 일(1) |
- 핵심은 값을 읽어내는 원칙을 활용해 구현하는 것이다. 하지만 기본적으로 구현할 때 굳이 이를 읽어낼 필요는 없다고 판단, 이번에는 읽어내는 단위를 나누는 조건들을 수치적으로 계산하는 방식으로 판단해본다.
- 위의 표를 통해 알 수 있듯, 기본적으로 아라비아 숫자 기준으론 3개의 숫자 단위 씩 묶어서 계산 되지만, 실제 발음하는 단위는 4개의 단위 씩 묶어서 판단된다. 또한, 각 4개씩 묶인 단위에서 첫번째 자리가 일, 마지막이 천에 해당한다고 볼 수 있다.
- 그러나 이때, 묶는 단위를 기준으로 해당 자리보다 더 상위 자릿숫자가 존재하지 않는다면, 1이 올 때, 단위숫자만 읽는다. (예 - 이백십일만원 vs 만원 )
- 중간에 0이 들어가면 당연히 발음에는 포함되지 않는다. 예를 들어 1, 000, 000원 이라고 한다면, 백만원 이 되고, 중간 단위가 생략되고, 이러면 어절에서 헷갈리게 만드는 원인이 된다.
아이디어
- 최초에는 각 단위를 클래스로 묶고, 클래스 기준으로 연산하는 구조도 생각해보았다.
- 하지만 서로 연계되는 면도 없지 않아 있고, 여러 번잡해지는 문제를 만나 순차적으로 해석하는 방식으로 회귀하였다.
- 이때 핵심은 각 자릿수가 가지는 원칙을 그대로 수치기준으로 돌리는 것이고, 이 핵심이 메서드 count_word에 담겨 있다.
- 특히나 어려웠던 부분은 각 발음 단위 기준 일의 자리의 문제였다. 만단위부터는 일의 자리 숫자가, 상위 자릿숫자가 존재하면
일만
이라고 읽을 수 있으나, 없다면 단독으로는만원
이렇게 읽히는 것이 내부 룰이었고, 이를 구현하는 것에 대해서는 해석의 힌트를 참고 하였다.
아쉬운 점
- 결국 엣지케이스를 발견하여, 해결을 하긴 했다. 하지만 이 과정의 시간이 많이 걸렸는데 그 가장 큰 이유가 ‘보이지 않기’ 때문이라고 생각이 들었다.
- 즉, 다른 풀이나 도전하시는 분들처럼 문자열을 만들어서 한글화 시키는 방법으로 우선 숫자 -> 한글화 시켰다고 한다면, 눈에 보이기 때문에 엣지 케이스의 유무를 더 빨리 파악하고 작업이 가능했을 것이다.
- 그러나 효율적으로 하겠단 생각에 수치적으로 계산하는 방식을 선택 했다보니 실제 결과물이 없고, 결과물이 없으니 디버깅을 하거나 엣지 케이스를 만들어내는 것에서 굉장한 비효율성을 보여주었다 ㅠㅠ..
풀이 코드
# 암아존 배조스씨를 위한 계좌이체 한글 음성 안내
# 최적화 버전
import sys
def count_word(number_part, unit):
result = 0
addtional_result = 0
for i, digit in enumerate(number_part):
# 첫자리 숫자에 대한 조건들
# 일반적인 숫자인 경우
if i == 0 and digit != 0 and digit != 1:
result += 1
elif i == 0 and digit == 1: # 최초숫자이면서 1인 경우, 일십~ 일조 까지 최초 일이 오는 경우를 검증
checker = False
for other_index in range(1, len(number_part)):
if int(number_part[other_index]) != 0:
checker = True # 일단위보다 높은 같은 발음 자리에서 숫자가 존재해 일이란 발음이 들어가야 하는경우
break
if checker:
result += 1
else:
addtional_result += 1 # 같은 단위 기준, 다른 숫자가 없어서 단위수만 붙으면 된다. 혹은 일만 붙어야 한다.
# 다른 자리숫자들의 값에 대한 카운트
if i != 0 and digit != 0:
if digit == 1:
result += 1
else:
result += 2
# 최종적으로 결과가 있고, 단위숫자가 만 이상이면, 단위숫자를 붙여준다.
if unit != 0 and result != 0:
addtional_result = 1
return result + addtional_result
def count_words(value):
value.reverse()
part = []
result = 0
number_unit = 0 # 단위 수
word_division = 0 # 어간의 숫자
temp = 0
for word_index, word in enumerate(value):
part.append(word)
if len(part) == 4 or (word_index + 1 == len(value)):
temp = count_word(part, number_unit)
number_unit += 1
part.clear()
if temp != 0:
word_division += 1
result += temp
temp = 0
result += 1
return result * word_division
k = int(input())
line = []
for i in range(k):
line.append(sys.stdin.readline())
total_result = 0
for i in range(k):
arr = []
for char in line[i].split(","):
if "원" in char:
char = char.replace("원\n", "")
for number in char:
arr.append(int(number))
total_result += count_words(arr)
print("어간 x 글자수 : ", total_result)