Jun 29 2008

Java / Windows에서 Runtime.exec() 배치 리턴값이 정확히 넘어오지 않음

분류: Lang.Java 태그: ,Heart @ 1:58 오전

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

Java가 아무래도 OS depedent 한 부분은 좀 깔끔하지가 못한 게 아닌가 생각이 드는 상황.

Runtime.exec() -> Process.waitFor() 나 Process.exitValue();
배치 파일에서 넘겨주는 값과 상관없이 0이 나온다.

대놓고 배치 파일에

exit /b 1

을 해도 0 이 나온다. 당연히 cmd 창에서 배치를 실행하고 echo %ERRORLEVEL% 을 하면 1이 나온다.

음… 배치에서 리턴 값 받아서 쉽게 가려고 했는데 안될라나보다.

아래는 배치를 실행하는 클래스.
에러 코드 받아오는 것 빼고는 정상적으로 동작하는 것으로 보아서는 코드 문제 같지는 않다.

ps. 제가 뭔가 잘못 알고 있는 부분이 있거나, Java에서 리턴값을 받을 수 있는 방법이 있으면 알려주시면 정말 감사하겠습니다.

package net.heartsavior.dev.util;
 
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
 
class ExecutorStreamRead extends Thread {
 
	private BufferedReader br = null;
 
	public ExecutorStreamRead(InputStream is) {
		br = new BufferedReader(
				new InputStreamReader(is) );
	}
 
	@Override
	public void run() {
		// TODO Auto-generated method stub
		super.run();
 
		String line;
		try {
			while ((line = br.readLine()) != null) {
				// TODO 로그
				System.out.println(line);
			}
 
			br.close();
		} catch (IOException e) {
			// TODO 예외 처리
			e.printStackTrace();
		}
	}
 
}
 
/**
 * @author Heart
 *
 */
public class WindowsFileExecutor implements LocalFileExecutor {
	public int execute(String filePath, String argString) 
		throws IOException {
 
		if( null == filePath )
			return 0;
 
		Process p = null;
 
		String curDir = System.getProperty("user.dir");
		File workDir = null;
 
		if( filePath.indexOf(":") == -1 )		// 상대 경로
			workDir = new File(curDir + getDirectoryPath(filePath));
		else											// 절대 경로
			workDir = new File(getDirectoryPath(filePath));
 
		if( null != argString )
			p = Runtime.getRuntime().exec(
				getCorrectWindowsFilePath(filePath) + " " + argString, null, workDir);
		else
			p = Runtime.getRuntime().exec(getCorrectWindowsFilePath(filePath), null, workDir);
 
		// TODO 로그
		System.out.println("Console Print ------------------------");
 
		ExecutorStreamRead readStdout = new ExecutorStreamRead(p.getInputStream());
		readStdout.start();
 
		ExecutorStreamRead readStdErr = new ExecutorStreamRead(p.getErrorStream());
		readStdErr.start();
 
		// TODO 로그
		System.out.println("End of Console Print -----------------");
 
		int errorCode = -1;
 
		try {
			errorCode = p.waitFor();
		} catch(InterruptedException ie) {
			throw new IOException();
		}
 
		if( errorCode == 0 )
			errorCode = p.exitValue();
 
		return errorCode;
	}
 
	public static String getCorrectWindowsFilePath(String filePath) {
		if( -1 == filePath.indexOf(" ") )
			return filePath;
 
		StringBuffer sb = new StringBuffer();
		sb.append("\"");
		sb.append(filePath);
		sb.append("\"");
 
		return sb.toString();
	}
 
	public static String getDirectoryPath(String filePath) {
		char delim = '\\';
 
		int lastDelim = filePath.lastIndexOf(delim);
 
		if( -1 == lastDelim ) {
 
			delim = '/';
 
			lastDelim = filePath.lastIndexOf(delim);
 
			if( -1 == lastDelim)
				return null;
		}
 
		return filePath.substring(0, lastDelim);
	}
}

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];
}


Jun 20 2008

‘셀프 넘버’ 문제

분류: Dev.Programming 태그: ,, Heart @ 4:44 오후

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

넥슨 입사시험 문제로 더 유명한 ‘셀프 넘버’ 문제

어떤 자연수 n이 있을 때, d(n)을 n의 각 자릿수 숫자들과 n 자신을 더한 숫자라고 정의하자.
예를 들어 d(91) = 9 + 1 + 91 = 101
이 때, n을 d(n)의 제네레이터(generator)라고 한다. 위의 예에서 91은 101의 제네레이터이다.

어떤 숫자들은 하나 이상의 제네레이터를 가지고 있는데, 101의 제네레이터는 91 뿐 아니라 100도 있다.
그런데 반대로, 제네레이터가 없는 숫자들도 있으며, 이런 숫자를 인도의 수학자 Kaprekar가
셀프 넘버(self-number)라 이름 붙였다.

예를 들어 1,3,5,7,9,20,31 은 셀프 넘버 들이다.

문제.
1 이상이고 5000 보다 작은 모든 셀프 넘버들의 합을 구하라

이게 문제인데…

규칙이 있을꺼라 생각하고 규칙을 찾아보려고 머리를 굴려 봐도, self number를 뽑아서 봐도…
아무리 생각해도 규칙을 못찾겠다 OTL

단지, self number 간의 차가 2가 몇 번 나오다가 11 여러 번, 12 한 번, 다시 11 여러 번 나온다는 정도?

그래서, 그냥 1 ~ 5000 까지의 수로 d(n)을 전부 만들어보는 방법을 사용했다.
자기 자신을 한 번 더하기 때문에 5000 이상은 계산할 필요가 없다.

#include <iostream>
using namespace std;
 
#define MAX_NUMBER		5000
 
bool g_selfNumber[MAX_NUMBER + 1];
 
void initSelfNumberArr();
int funcGenerator(int number);
 
int main(void)
{
	int sum = 0;
 
	initSelfNumberArr();
 
	for( int i = 1 ; i < = MAX_NUMBER ; i++ )
	{
		int generator = funcGenerator(i);
 
		if( generator <= MAX_NUMBER )
			g_selfNumber[generator] = false;
	}
 
	for( int i = 1 ; i <= MAX_NUMBER ; i++ )
	{
		if( g_selfNumber[i] == true )
		{
			//cout << "Self Number found : " << i << endl;
			sum += i;
		}
	}
 
	cout << "Sum of self number (1~" << MAX_NUMBER << ") is " << sum << endl;
 
	return 0;
}
 
void initSelfNumberArr()
{
	for( int i = 0 ; i <= MAX_NUMBER ; i++ )
		g_selfNumber[i] = true;
}
 
int funcGenerator(int number)
{
	int total = 0;
 
	int n = number, mod;
 
	do {
		mod = n % 10;
		n = n / 10;
 
		total += mod;
	} while( n > 0 );
 
	total += number;
 
	return total;
}
</iostream>

뒷 쪽 »