| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 가독성
- vscode
- redis
- 문자열 반복문
- 생성형AI
- mobaXterm
- RestController
- SPLIT
- Repository
- Generic
- 일관성
- StringTokenizer
- StringBuilder
- Controller
- reverse()
- 백준
- 런타임에러
- putty
- spring
- outfitanyone
- 생활코딩
- Java
- 문자열
- JDoodle
- Component
- prettier
- 백준 문자열
- 다이얼
- Service
- JAVA 설치
- Today
- Total
gone
#[백준] 1152 단어의 개수(StringTokenizer 클래스) 본문

이번 문제는 아무리 봐도 내가 틀린 이유를 도저히 알 수가 없어서 답안지를 참고했으므로 오답노트의 형식으로 풀어갈 것이다. 참고 사이트는 늘 그렇듯 아래와 같다.
제출1) 에러
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str = br.readLine();
// Q. 문자열에 들어가 있는 단어의 총개수 구하기
// 조건1. 같은 문자여도 카우트해야함.
// 조건2. 앞뒤 공백이 있을수 있다.
String[] strarr = str.trim().split(" ");
System.out.println(strarr.length);
}
}
split() 을 이용해서 오답자가 상당히 많이 존재하는 것 같다. 우선 split () 메서드에 대해서 정확히 파악해야 될 것 같다.
split () 이란?
/*
* Splits this string around matches of the given regular expression.
* This method works as if by invoking the two-argument split method with the given expression and a limit argument of zero.
Trailing empty strings are therefore not included in the resulting array.
* The string "boo:and:foo", for example, yields the following results with these expressions:
* Regex Result
* : `` { "boo", "and", "foo" }}
* o `` { "b", "", ":and:f" }}
*/
public String[] split(String regex) {
return split(regex, 0);
}
" 이 메서드는 주어진 정규식에 일치하는 부분을 기준으로 문자를 나눈다. "
이 메서드는 주어진 표현식과 제한 인자 0을 둔 인자를 사용하여 두 인자로 된 `split` 메서드를 호출하는 것과 같은 방식으로 동작합니다. 따라서 결과 배열에는 끝에 있는 빈 문자열이 포함되지 않습니다.
java 공식 api 문서에서 발최한 글이다. 결국 가장 중요한 단어는 정규식에 해당하는 부분을 기준으로 나누기 때문에 제출 1)의 코드도 맞잖아!! 했지만 반전이 숨어있었다.
split함수를 더 깊게 파보게 되면 아래와 같은 코드를 찾을 수 있다.
우선,
제출 1) 코드를 다시 실행해서 공백 또는 줄 바꿈만 해보자. 그럼 결과가 1이 나오는 것을 확인할 수 있다.
이제 split함수에 대해 알아보자. java api 문서에서는 아래와 같이 설명한다.
int off = 0;
int next = 0;
boolean limited = limit > 0;
ArrayList<String> list = new ArrayList<>();
while ((next = indexOf(ch, off)) != -1) {
if (!limited || list.size() < limit - 1) {
list.add(substring(off, next));
off = next + 1;
} else { // last one
//assert (list.size() == limit - 1);
int last = length();
list.add(substring(off, last));
off = last;
break;
}
}
// If no match was found, return this
if (off == 0)
return new String[]{this};
split을 이용한 정규식처리과정에서 매칭된 값도 없고 처리할 값도 없을 경우 `this`자기 자신을 return 한다는 뜻이다.
따라서 bufferedReader는 공백도 입력받기 때문에 split(" ")만을 이용해서 문제를 접근할 시 공백/줄 바꿈에 대한 예외처리가 되지 않아 오류가 난다는 것을 알 수 있다.
제출 1) 수정코드
예외처리 하나만 해주면 정답으로 인정해 준다.
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str = br.readLine();
String[] strarr = str.trim().split(" ");
if (strarr.length > 0 && strarr[0].equals("")) {
// 첫번째 배열의 값이 빈문자열'' 이라면 0을 출력해야한다.
System.out.println(0);
} else {
System.out.println(strarr.length);
}
}
}
제출 2) StringTokenizer 클래스 사용
import java.util.Scanner;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String S = in.nextLine();
in.close();
// st 에 공백을 기준으로 나눈 토큰들을 st 에 저장한다
StringTokenizer st = new StringTokenizer(S," ");
// countTokens() 는 토큰의 개수를 반환한다
System.out.println(st.countTokens());
}
}
StringTokenizer()?? 이건 또 뭐지.. ㅠㅠ
[Java] StringTokenizer와 Split() 메서드 언제 써야할까?
우선 StringTokenizer에 대해 알아보자. java.util.StringTokenizer 클래스란? 긴 문자열을 지정된 구분자(delimiter)를 기준으로 토큰(token)이라는 여러 개의 문자열로 잘라내는 데 사용된다. 예) “100,200,300,4
velog.io
StringTokenizer ?
긴 문자열을 지정된 구분자(delimiter)를 기준으로 토큰(token)이라는 여러 개의 문자열로 잘라내는데 사용된다.split과의 차이점이라면
1. split의 구분자(delimiter)은 정규식코드로 작성되어져야되기 때문에 복잡하지만 StringTokenizer 은 아니다.
아래의 코드를 보면 한번에 이해할 수 있다.
String ex = "x=100*(200+300)/2";
System.out.print("split() \t\t => ");
// 1. split() 메소드를 사용한 문자열 자르기
String[] tokens = ex.split("[+*/=()]+");
for (String token : tokens) {
// 빈 문자열은 출력하지 않음
if (!token.isEmpty()) {
System.out.print(token + " ");
}
}
System.out.println();
System.out.print("StringTokenizer 클래스 => ");
// 2. StringTokenizer 클래스를 사용한 문자열 자르기
StringTokenizer st = new StringTokenizer(ex, "+=*/()");
while (st.hasMoreTokens()) {
System.out.print(st.nextToken() + " ");
}

2. split() 과 다르게 공백은 토큰으로 인식하지 않는다는점이다.
제출1) 에서 공백을 토큰을 인식해서 단어의 개수가 1이나와 오류가 나왔지만 StringTokenizer을 사용하게되면 공백을 토큰으로 인식하지 않게 되므로 0 이 나와서 정답처리가 된다.
StringTokenizer와 Split의 차이
StringTokenizerSplit()
| java.util에 포함된 클래스다. | String 클래스에 속해있는 메소드 |
| 문자로 문자열을 구분 | 정규표현식으로 구분 |
| 오직 단 한 문자의 구분자만 사용 가능 | 정규표현식을 이용하면 두 문자 이상의 구분자도 사용 가능 |
| 결과값이 문자열 String | 결과값이 문자열 배열 String[] |
| 빈 문자열을 토큰으로 인식하지 않음 | 빈 문자열을 토큰으로 인식함 |
→ 데이터 양이 적을 때 배열에 담아 반환하는 split는 데이터를 바로 잘라서 반환해주는 StringTokenizer보다 느릴 수 있다.
'알고리즘' 카테고리의 다른 글
| #[백준] 1157 단어공부 (0) | 2024.01.12 |
|---|---|
| #[백준] 2675 문자열 반복 (StringBuilder 클래스) (0) | 2024.01.11 |
| #[백준] 11720 숫자의 합 (1) | 2024.01.11 |