자바를 이용한 알고리즘을 풀때 보통 Scanner 클래스를 이용하여 입력 받기도 하지만 대부분의 경우 BufferedReader 로 String 으로 입력을 받고 StringTokenizer 를 이용하여 띄어쓰기를 통해서 구분하여 입력 받는 것을 본 기억이 있다.
입력 부분이기는 하나 생각보다 사용하는 메서드도 많고 여간 까다로운 것이 아니라 한번 제대로 이해해 보기로 했다.
| 생성자 / 메서드 | 설명 |
|---|---|
| StringTokenizer(String str, String delim) | 문자열(str)을 지정된 구분자(delim)로 나누는 StringTokenizer를 생성 (구분자는 토큰으로 간주되지 않음) |
| StringTokenizer(String str, String delim, boolean returnDelims) | 문자열 (str)을 지정된 구분자(delim)로 나누는 StringTokenizer를 생성하고 returnDelims 의 값을 true 로 하면 구분자도 토큰으로 간주된다. |
| int countTokens() | 전체 토큰의 수를 반환한다. |
| boolean hasMoreTokens() | 토큰이 남아 있는지 알려준다 |
| String nextToken() | 다음 토큰을 반환한다. |
1)
package ch09_java_lang_package.StringTokenizerEx;
import java.util.StringTokenizer;
public class StringTokenizerEx01 {
public static void main(String[] args) {
String source = "100,200,300,400";
StringTokenizer st = new StringTokenizer(source,",");
// 만약 두번째 인자가 없으면 디폴트로 공백문자, 개행문자로 취급
while (st.hasMoreTokens()) {
System.out.println(st.nextToken());
}
}
}

,를 구분으로 하여 100, 200, 300, 400 을 토큰으로 저장한다.
2)
package ch09_java_lang_package.StringTokenizerEx;
import java.util.StringTokenizer;
public class StringTokenizerEx02 {
public static void main(String[] args) {
String expression = "x=100*(200+300)/2";
StringTokenizer st = new StringTokenizer(expression, "+-*/=()", true);
while(st.hasMoreTokens()) {
System.out.println(st.nextToken());
}
}
}

위처럼
returnDelims를 true 로 하게 되면 지정된delim도 토큰으로 지정되어st.hasMoreTokens를 이용하여 출력을 할 수 있다.
""로 묶여진delim의 경우 합쳐서가 아닌 하나하나의 문자로 구분된다.
(false 인 경우 연산자 제외 숫자만 나옴)
3)
package ch09_java_lang_package.StringTokenizerEx;
import java.util.StringTokenizer;
public class StringTokenizerEx03 {
public static void main(String[] args) {
String source = "1,김천재,100,100,100|2,박수재,95,80,90|3,이자바,80,90,90";
StringTokenizer st = new StringTokenizer(source, "|");
while (st.hasMoreTokens()) {
String token = st.nextToken();
StringTokenizer st2 = new StringTokenizer(token, ",");
while (st2.hasMoreTokens()) {
System.out.println(st2.nextToken());
}
System.out.println("----------------");
}
}
}

위 코드를 보면
|문자를 기준으로 토큰을 생성하고 각 토큰을 또다시,를 기준으로 토큰들을 생성한다. (여러번의 토큰 사용) 그리고 각 토큰들을 출력하게 되는 코드예시이다.
4)
package ch09_java_lang_package.StringTokenizerEx;
import java.util.StringTokenizer;
public class StringTokenizerEx04 {
public static void main(String[] args) {
String input = "삼십만삼천백십오";
System.out.println(input);
System.out.println(hangulToNum(input));
}
public static long hangulToNum(String input) { // 한글을 숫자로 변경하는 메서드
long result = 0;
long tmpResult = 0;
long num = 0;
final String NUMBER = "영일이삼사오육칠팔구";
final String UNIT = "십백천만억조";
final long[] UNIT_NUM = {10, 100, 1000, 10000, (long) 1e8, (long) 1e12}; // 각각 십, 백, 천, 만, 억, 조 ...
StringTokenizer st = new StringTokenizer(input, UNIT, true);
while (st.hasMoreTokens()) {
String token = st.nextToken();
int check = NUMBER.indexOf(token);
if (check == -1) { // 0~9 가 아닌 경우 (단위 숫자)
if ("만억조".indexOf(token) == -1) {
tmpResult += (num != 0 ? num : 1) * UNIT_NUM[UNIT.indexOf(token)];
} else {
tmpResult += num;
result += (tmpResult != 0 ? tmpResult : 1) * UNIT_NUM[UNIT.indexOf(token)];
tmpResult = 0;
}
num = 0;
} else {
num = check;
}
}
return result + tmpResult + num;
}
}

tokenizer를 이용하여 한글을 숫자로 바꾸는 다소 까다로운 문제이다.
tmpResult는 만억조와 같은 큰 단위가 나오기 전까지 십백천 단위의 값을 저장하기 위한 임시공간이고 result 가 실제 값을 저장하기 위한 공간이다.
한글로 된 숫자로 구분자(단위)로 잘라서 토큰이 숫자면 num 에 저장하고 단위면 num에 단위를 곱해서 tmpResult 에 저장한다.
ex) "삼십" 은 '3 * 10 = 30' 이 되어 tmpResult 에 저장된다.
"만삼천" 과 같이 숫자 없이 바로 단위로 시작하는 경우 nu의 값이 0이기 때문에 단위의 값을 곱해도 결과가 0이 되므로 삼항연산자를 이용해 num의 값을 1로 바꾼후 단위 값을 곱하도록 하였다.
그다음에 "만억조" 와 같이 큰 단위가 오면 tmpResult에 저장된 값에 큰 단위 값을 곱해서 result 에 저장하고 tmpResult는 0으로 초기화 한다.
ex) "삼십만" 은 tmpResult에 저장되어 있던 30에 10000을 곱해서 저장하고, tmpResult 는 0으로 초기화 한다.
5)
package ch09_java_lang_package.StringTokenizerEx;
import java.util.StringTokenizer;
public class StringTokenizerEx05 {
public static void main(String[] args) {
String data = "100,,,200,300";
String[] result = data.split(",");
StringTokenizer st = new StringTokenizer(data, ",");
for(int i=0;i<result.length;i++){ // 단순히 split을 이용한 경우
System.out.print(result[i] + "|");
}
System.out.println("개수 : " + result.length);
int i=0;
for(;st.hasMoreElements();i++){
System.out.print(st.nextElement() + "|");
}
System.out.println("개수 : " + i);
}
}

StringTokenizer와split의 차이를 단적으로 보여주는 예시이다 위와 같이,가 여러개 있고 이경우split을 사용하게 되면 길이가 5가 되는 반면
StringTokenizer를 이용하게 된다면 해당 값을 무시해버리면서 다른 값만 쪽 뽑아오게 되면서 해당 길이가 3이 되는 원하는 목표를 이룰 수 있게 된다.