Jun 25 2008

문자열로 된 숫자를 입력받아 더하거나 빼는 프로그램

분류: Dev.Programming 태그: ,, Heart @ 10:51 오전

Trackback : http://dev.heartsavior.net/archives/148/trackback/

한컴 입사시험 문제라고 한다
(최근 입사문제인가 싶어서 안올리고 있었는데, 구글에서 검색해볼 껄 그랬다 -_-;; 2005년 쯤에 KLDP에 있네.)

문제 : 문자열로 된 숫자를 입력받아 더하거나 빼는 프로그램을 만드시오

처리조건
- 문자열로 된 값을 입력받아, 모두 더한 값을 문자열로 출력한다.
- 마이너스 값이 될 수 있으며 기호는 ‘-’ 문자를 사용한다.
- 최대 입력은 ‘1억’이며 그 이상은 에러처리를 한다.

입력 예)
이백원 + 오천원 - 만원

출력 예)
-사천팔백원

출처가 된 커뮤니티에서는 쉽다는 의견들이 많았는데…
결과에 대해 ‘일십만…’ 이렇게 표현하지 않고 ‘만천일원…’ 이렇게 일반적으로 말하는 형식으로 만드려면 출력할 때 손을 좀 많이 대야 한다.
(int 내에서 사칙연산을 한다는 전제 하에)사칙연산은 당연히 문제가 안되고, 어차피 입력 값을 파싱하는 부분과 사칙연산의 결과를 다시 한글로 출력하는 부분이 핵심이라 할 수 있다. 역시 한컴에서 출제할 만한 문제인 듯.

아래는 내가 푼 코드…
버그를 하나 알고 있지만, 출제의도와는 관계없는 것 같아 놔둔다. 버그를 해결하려면 BigInteger가 필요…
입력값이 int 범위를 넘어가면 오버플로우가 일어나서 undefined behavior를 보일 수 있다.

#include <iostream>
using namespace std;
 
#define REP1_SIZE		10
#define REP2_SIZE		4
#define REP3_SIZE		3
 
char g_numberHangul[REP1_SIZE][3] = {"영", "일", "이", "삼", "사", "오", "육", "칠", "팔", "구"};
char g_numberRep2Hangul[REP2_SIZE][3] = {"영", "십", "백", "천"};
char g_numberRep3Hangul[REP3_SIZE][3] = {"영", "만", "억"};
 
#define MAX_INPUT_NUMBER	100000000		// 억
 
#define MODE_INIT		0
#define MODE_PLUS		1
#define MODE_MINUS		2
 
#define CHAR_PLUS		'+'
#define CHAR_MINUS		'-'
#define CHAR_SPACE		' '
 
#define STRING_WON		"원"
 
int getIndexOnHangulArray(char arrHangulSrc[][3], int arrLength, char hangul[3]);
int pow_int(int a, int x);
void printNumToHangul(int number);
void printNumToHangulRep2Recur(int number, int rep2Idx);
void printNumToHangulRep3Recur(int number, int rep3Idx);
 
int main(void)
{
	char input[1024], temp[3];
 
	int sum = 0, curVal = 0, mode = MODE_INIT, curRep3Val = 0, curTotalVal = 0;
 
	cout < < "계산할 문자열을 입력하세요" << endl;
	cin.getline(input, 1024);
 
	char * pCur = input;
 
	while( *pCur )
	{
		// 한글임
		if( *pCur & 0x80 )
		{
			strncpy_s(temp, pCur, 2);
			temp[2] = '\0';
 
			pCur += 2;
 
			// 어디에 소속되는 지 체크
			int index = getIndexOnHangulArray(g_numberHangul, REP1_SIZE, temp);
 
			if( index != -1 )
			{
				// 일 자리
				curVal = index;
 
				continue;
			}
 
			index = getIndexOnHangulArray(g_numberRep2Hangul, REP2_SIZE, temp);
 
			if( index != -1 )
			{
				// 십, 백, 천
				curRep3Val += pow_int(10, index) * (curVal > 0 ? curVal : 1);
				curVal = 0;
 
				continue;
			}
 
			index = getIndexOnHangulArray(g_numberRep3Hangul, REP3_SIZE, temp);
 
			if( index != -1 )
			{
				// 만, 억, ...
				curRep3Val += curVal;
 
				curTotalVal += pow_int(10, 4 * index) * 
						(curRep3Val > 0 ? curRep3Val : 1) ;
 
				curVal = 0;
				curRep3Val = 0;
 
				continue;
			}
 
			// 원
			if( strcmp(temp, STRING_WON) == 0 )
			{
				// 마지막 자리 숫자를 더함
				curTotalVal += curRep3Val;
				curTotalVal += curVal;
 
				cout < < "DEBUG]숫자 인식됨 : " << curTotalVal << endl;
 
				// 입력값 한도가 넘음
				if( curTotalVal > MAX_INPUT_NUMBER )
				{
					// 에러!!
					cout < < "Error occured, please check input string(Too Large Number)" << endl;
					exit(-1);
				}
 
				switch( mode )
				{
				case MODE_INIT:
					sum = curTotalVal;
					break;
 
				case MODE_PLUS:
					sum += curTotalVal;
					break;
 
				case MODE_MINUS:
					sum -= curTotalVal;
					break;
 
				default:
					// 에러!!
					cout << "Error occured, please check input string" << endl;
					exit(-1);
				}
 
				curTotalVal = 0;
				curRep3Val = 0;
				curVal = 0;
			}
			else		// 숫자와 관계없는 2byte 문자가 입력됨
			{
				// 에러!!
				cout << "Error occured, please check input string" << endl;
				exit(-1);
			}
		} // *pCur & 0x80
		else
		{
			// mode
			switch( *pCur )
			{
			case CHAR_PLUS:
				mode = MODE_PLUS;
				break;
 
			case CHAR_MINUS:
				mode = MODE_MINUS;
				break;
 
			case CHAR_SPACE:
				break;
 
			default:		// 사칙연산과 관계없는 1byte 문자가 입력됨				
				cout << "Error occured, please check input string" << endl;
				exit(-1);
			}
 
			pCur++;
		} // else 
 
	} // while(*pCur)
 
	//cout << "DEBUG] Sum is " << sum << endl;
	printNumToHangul(sum);
 
	return 0;
}
 
int getIndexOnHangulArray(char arrHangulSrc[][3], int arrLength, char hangul[3])
{
	for( int i = 0 ; i < arrLength ; i++ )
	{
		if( strncmp(arrHangulSrc[i], hangul, 2) == 0 )
			return i;
	}
 
	return -1;
}
 
int pow_int(int a, int x)
{
	int n = 1;
 
	if( 0 == x )
		return 1;
 
	for( int i = 1; i <= x ; i++ )
 
 
 
 
		n *= a;
 
	return n;
}
 
void printNumToHangul(int number)
{
	// 0
	if( number == 0 )
	{
		cout << "영원" << endl;
		return;
	}
 
	// 음수
	if( number < 0 )
	{
		cout << "-";
		number *= -1;
	}
 
	printNumToHangulRep3Recur(number, 0);
 
	cout << endl;
}
 
void printNumToHangulRep3Recur(int number, int rep3Idx)
{
	int n = number / 10000;
	int mod = number % 10000;
 
	// 윗 자리를 먼저 출력한다.
	if( n > 0 )
		printNumToHangulRep3Recur(n, rep3Idx + 1);
 
	// 4 자리로 끊은 나머지를 출력한다.
 
	// 나머지가 0이면 단위도 출력하지 않는다
	if( mod == 0 )
		return;
 
	// 예외 처리 : 4 자리로 끊은 나머지가 1인 경우 만 자리와 일/억/조/... 자리는 쓰는 방법이 다르다.
	// 만 단위만 1만 => 만, 나머지는 1 = 일, 1억=일억, 1조=일조, ...
	if( mod == 1 )
	{
		if( rep3Idx != 1 )
			cout < < g_numberHangul[mod];
	}
	else if( mod > 1 )
		printNumToHangulRep2Recur( mod, 0 );
 
	// 단위를 출력한다.
	if( rep3Idx == 0 )
		cout < < STRING_WON;
	else
		cout << g_numberRep3Hangul[rep3Idx];
}
 
void printNumToHangulRep2Recur(int number, int rep2Idx)
{
	int n = number / 10;
	int mod = number % 10;
 
	// 윗 자리를 먼저 출력한다.
	if( n > 0)
		printNumToHangulRep2Recur(n, rep2Idx + 1);
 
	// 현재 자리를 출력한다.
	if( mod == 0 )
		return;
 
	if( mod == 1 )
	{
		// 4자리씩 끊었을 때 마지막 자리일 때만 '일' 이라고 출력한다. 나머지는 '일'을 출력하지 않는다.
		// 4자리 자체가 1일 경우는 printNumToHangulRep3Recur() 에서 처리한다.
		if( rep2Idx == 0 )
			cout < < g_numberHangul[mod];
	}
	else
		cout << g_numberHangul[mod];
 
	// 단위를 출력한다.
	if( rep2Idx > 0 )
		cout < < g_numberRep2Hangul[rep2Idx];
}