관련지식
javascript, padStart

요즘은 많이 없어졌지만 예전엔 은행 홈페이지 또는 어플에서 이체할때 이체 금액을 입력하면 금액을 한글로 변환해서 보여주었습니다. 어쩌면 세금계산서와 관련된 회계 시스템에선 여전히 있을지도 모르겠네요

이번엔 금액 또는 숫자를 한글로 변환하는 함수를 만들어보고자 합니다.

변환 규칙

금액이 123456789 라는 숫자는 1억 2345만 6789 를 뜻합니다. 한글로 쓴다면 ‘일억 이천삼백사십오만 육천칠백팔십구’ 가 되겠죠. 먼저 변환 규칙을 정리해보겠습니다.

  1. 숫자는 뒤에서 부터 4자리마다 단위가 바뀐다.(만, 억, 조 …)
  2. 4자리 마다 숫자를 읽는 방법은 동일(단위만 달라짐)
    123456789 에서 1, 2345, 6789 는 단위만 다를뿐 똑같은 규칙으로 읽는다.
  3. 숫자 0은 읽지 않는다. 만약 해당 단위에 읽을수 있는 숫자가 없으면 단위도 읽지 않는다.
    10000 -> 일만, 300000050 -> 삼억오십(만단위에는 읽을 숫자가 없다)

이 규칙에 따라 만들어보겠습니다.

코딩

로직을 제외한 함수의 내용은 아래와 같습니다.

  1. function num2han(num) {
  2. num = parseInt((num + '').replace(/[^0-9]/g, ''), 10) + ''; // 숫자/문자/돈 을 숫자만 있는 문자열로 변환
  3. if(num == '0')
  4. return '영';
  5. var number = ['영', '일', '이', '삼', '사', '오', '육', '칠', '팔', '구'];
  6. var unit = ['', '만', '억', '조'];
  7. var smallUnit = ['천', '백', '십', ''];
  8. var result = []; //변환된 값을 저장할 배열
  9. //로직이 들어갈 위치
  10. return result.join('');
  11. }

함수의 첫줄이 지저분하게 되어있는데 파라미터 num 이 숫자, 문자로 들어올것에 대비한 코드입니다. 이 함수는 아래처럼 파라미터에 숫자, 문자, 금액을 사용할수가 있게 될것입니다. 물론 저렇게 하지 않고 typeof 키워드를 이용하여 변수의 타입에 맞는 변환만 할수도 있습니다.

  1. num2han('1,234,567원');
  2. num2han(12345678);
  3. num2han('123456789');

이번엔 숫자가 몇개의 단위로 구성되었는지 확인하고 자릿수를 네자리로 규격화하는 작업을 합니다. 만약 값이 119 일 경우 0이 하나 채워져서 0119로 바꾸게 됩니다. 0 때문에 이상하게 읽을 걱정은 하지 않아도 됩니다. 0은 읽지 않으니까요!

  1. var unitCnt = Math.ceil(num.length / 4); //단위 갯수. 숫자 10000은 일단위와 만단위 2개이다.
  2. num = num.padStart(unitCnt * 4, '0') //4자리 값이 되도록 0을 채운다

이번엔 정규표현식으로 숫자를 4자리마다 분리할겁니다. 만약 ‘123,456원’ 을 입력했다면 앞의 과정을 거치면서 8자리 문자 ‘00123456’ 으로 바뀌었을것이고, 이번 로직이 실행되면서 [‘0012’, ‘3456’] 값이 만들어지게 됩니다.

  1. var regexp = /[\w\W]{4}/g; //4자리 단위로 숫자 분리
  2. var array = num.match(regexp);

위에서 만들어진 값은 단위만 다를뿐 동일하게 읽으면 됩니다. 0012 는 ‘일십이’ 가 되고 3456은 ‘삼천사백오십육’이 됩니다. 숫자를 한글로 바꾸는 함수가 하나 있으면 좋겠네요.

  1. //여기로 들어오는 값은 무조건 네자리이다. 1234 -> 일천이백삼십사
  2. function _makeHan(text) {
  3. var str = '';
  4. for(var i = 0; i < text.length; i++) {
  5. var num = text[i];
  6. if(num == '0') //0은 읽지 않는다
  7. continue;
  8. str += number[num] + smallUnit[i];
  9. }
  10. return str;
  11. }

_makeHan() 함수에 네자리 숫자를 넣으면 천단위 이내의 한글로 변환된 값이 나옵니다. 이 값에 만, 억, 조, 경, 해 등의 단위를 붙이면 됩니다. _makeHan() 함수에는 무조건 네자리가 입력되기 때문에 앞자리부터 계산을 해도 되지만, 전체 숫자는 몇자리가 될지 모르므로 단위 계산을 할때 뒷자리(낮은 자릿수) 부터 세는게 쉽습니다.

  1. //낮은 자릿수에서 높은 자릿수 순으로 값을 만든다(그래야 자릿수 계산이 편하다)
  2. for(var i = array.length - 1, unitCnt = 0; i >= 0; i--, unitCnt++) {
  3. var hanValue = _makeHan(array[i]); //한글로 변환된 숫자
  4. if(hanValue == '') //값이 없을땐 해당 단위의 값이 모두 0이란 뜻.
  5. continue;
  6. result.unshift(hanValue + unit[unitCnt]); //unshift는 항상 배열의 앞에 넣는다.
  7. }

이제 테스트를 해보면 됩니다. 아래의 코드를 실행했을때 모든 테스트 결과가 true로 나온다면 잘 완성된 것입니다.

  1. console.log(num2han(1234) == '일천이백삼십사');
  2. console.log(num2han(12345) == '일만이천삼백사십오');
  3. console.log(num2han(123456) == '일십이만삼천사백오십육');
  4. console.log(num2han('1,234,567원') == '일백이십삼만사천오백육십칠');
  5. console.log(num2han(12345678) == '일천이백삼십사만오천육백칠십팔');
  6. console.log(num2han('123456789') == '일억이천삼백사십오만육천칠백팔십구');
  7. console.log(num2han(1234567890) == '일십이억삼천사백오십육만칠천팔백구십');
  8. console.log(num2han(12000) == '일만이천');
  9. console.log(num2han(01) == '일');
  10. console.log(num2han(0) == '영');
  11. console.log(num2han(300000000) == '삼억');

정리

여기서 만든 로직은 값을 아래와 같이 변환합니다.

  1. 4자리 숫자가 되도록 0 padding 추가
    123456 -> ‘00123456’
  2. 4자리 숫자로 분리
    ‘00123456’ -> [‘0012’, ‘3456’]
  3. 한글로 변환
    0012 -> 일십이, 3456 -> 삼천사백오십육
  4. 단위 붙이고 모든 숫자 합치기
    일십이 + 만 + 삼천사백오십육

이 기능을 구현할때 많은 if 를 추가하여 loop 내 로직을 복잡하게 만드는 경우가 있는데, 심플한게 가장 좋은것 같습니다. 브라우저에서 실행할것을 감안하여 만들었는데 각자의 환경에 맞게 수정해서 쓰셔도 될것 같습니다. padStart() 는 익스플로러를 지원하지 않으므로 polyfill 을 적용해야 할수도 있습니다. 아니면 자체 사용중인 padding 함수로 바꿔서 쓰셔도 됩니다.

최종 소스

  1. console.log(num2han(1234) == '일천이백삼십사');
  2. console.log(num2han(12345) == '일만이천삼백사십오');
  3. console.log(num2han(123456) == '일십이만삼천사백오십육');
  4. console.log(num2han('1,234,567원') == '일백이십삼만사천오백육십칠');
  5. console.log(num2han(12345678) == '일천이백삼십사만오천육백칠십팔');
  6. console.log(num2han('123456789') == '일억이천삼백사십오만육천칠백팔십구');
  7. console.log(num2han(1234567890) == '일십이억삼천사백오십육만칠천팔백구십');
  8. console.log(num2han(12000) == '일만이천');
  9. console.log(num2han(01) == '일');
  10. console.log(num2han(0) == '영');
  11. console.log(num2han(300000000) == '삼억');
  12. function num2han(num) {
  13. num = parseInt((num + '').replace(/[^0-9]/g, ''), 10) + ''; // 숫자/문자/돈 을 숫자만 있는 문자열로 변환
  14. if(num == '0')
  15. return '영';
  16. var number = ['영', '일', '이', '삼', '사', '오', '육', '칠', '팔', '구'];
  17. var unit = ['', '만', '억', '조'];
  18. var smallUnit = ['천', '백', '십', ''];
  19. var result = []; //변환된 값을 저장할 배열
  20. var unitCnt = Math.ceil(num.length / 4); //단위 갯수. 숫자 10000은 일단위와 만단위 2개이다.
  21. num = num.padStart(unitCnt * 4, '0') //4자리 값이 되도록 0을 채운다
  22. var regexp = /[\w\W]{4}/g; //4자리 단위로 숫자 분리
  23. var array = num.match(regexp);
  24. //낮은 자릿수에서 높은 자릿수 순으로 값을 만든다(그래야 자릿수 계산이 편하다)
  25. for(var i = array.length - 1, unitCnt = 0; i >= 0; i--, unitCnt++) {
  26. var hanValue = _makeHan(array[i]); //한글로 변환된 숫자
  27. if(hanValue == '') //값이 없을땐 해당 단위의 값이 모두 0이란 뜻.
  28. continue;
  29. result.unshift(hanValue + unit[unitCnt]); //unshift는 항상 배열의 앞에 넣는다.
  30. }
  31. //여기로 들어오는 값은 무조건 네자리이다. 1234 -> 일천이백삼십사
  32. function _makeHan(text) {
  33. var str = '';
  34. for(var i = 0; i < text.length; i++) {
  35. var num = text[i];
  36. if(num == '0') //0은 읽지 않는다
  37. continue;
  38. str += number[num] + smallUnit[i];
  39. }
  40. return str;
  41. }
  42. return result.join('');
  43. }