반응형

 

 

 

Scanner

 

 

Scanner는 사용자로부터의 입력을 읽기 위한 클래스이며. 주로 키보드 입력을 읽거나 파일에서 데이터를 읽을 때 사용된다.

코딩 테스트를 비롯한 PS 문제에서 BufferedReader와 함께 입력을 받기 위해서 많이 사용된다.

 

Scanner은 BufferedReader에 비해서 사용하기 용이한 메서드들을 클래스에서 많이 제공한다. 따라서 BufferedReader에 비해서 자료형을 처리하거나 간단하게 입력을 처리하기에 용이하다. 

그렇지만 데이터를 파싱하기 위해서 내부적으로 정규 표현식 등을 사용하여 BufferedReader에 비해 내부적으로 복잡한 과정을 거쳐 처리 시간이 더 오래 걸린다.

 

따라서 입력량이 고정되어 있고, 그 양이 많지 않은 경우에는 Scanner를 사용하여 편리하게 입력을 받는 것을, 입력량이 정해져 있지 않거나, 많은 경우에는 Scanner보다 BufferedReader의 사용을 고려하는 것이 좋다.

  • 필자는 PS 문제를 풀 때 보통 10개 내외의 Token 정도를 읽어들이는 정도라면 Scanner를 사용하고, 그렇지 않은 경우에는 BufferedReader를 사용한다.

 


기본 입력

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        // Scanner 객체 생성
        Scanner scanner = new Scanner(System.in);

        // 정수 입력 받기
        System.out.print("정수를 입력하세요: ");
        int intValue = scanner.nextInt();
        System.out.println("입력한 정수: " + intValue);

        // 실수 입력 받기
        System.out.print("실수를 입력하세요: ");
        double doubleValue = scanner.nextDouble();
        System.out.println("입력한 실수: " + doubleValue);
        
        // 공백으로 구분된 문자열 입력받기
        System.out.print("이름을 입력하세요: ");
        String name = scanner.next();
        System.out.println("입력한 이름: " + name);

        // 버퍼 비우기
        scanner.nextLine(); // 정수, 실수 입력 후에 버퍼에 남아있는 개행문자 제거

        // 문자열 한 줄 입력 받기
        System.out.print("문자열을 입력하세요: ");
        String stringValue = scanner.nextLine();
        System.out.println("입력한 문자열: " + stringValue);

        // Scanner 객체 닫기
        scanner.close();
    }
}

 

1. 수치 입력 받기 : nextInt(), nextDouble(), nextLong()..

2. 공백으로 구분된 단어(문자열) 입력받기 : next() (공백 이전의 문자열을 반환하고, 공백은 무시한다)

3. 한 줄의 문자열 입력받기 : nextLine()

- 동시에 위의 공백으로 구분된 입력들에 포함되어 있는 개행을 초기화시키는 역할도 한다. 만약 next()로 단어를 입력받은 이후 nextLine()을 통해 문자열 한 줄을 입력받으려고 한다면, nextLine()을 이전에 한번 호출하여 next()에 포함된 개행을 초기화 시켜주어야 한다.

 

 

 

 


EOF

Scanner scanner = new Scanner(System.in);

while (scanner.hasNext()) {
    int num = scanner.nextInt();
    System.out.println("입력한 정수: " + num);
}

 

만약 입력을 얼마나 받을 지 명시되지 않은 채, 입력이 끝날 때 까지 모든 입력을 처리해야 한다고 하면 EOF(End of File, 데이터 소스로부터 더 이상 읽을 수 있는 데이터가 없음)이 나올 때 까지 입력을 처리해야 한다.

 

Scanner 클래스에서는 hasNext()라는 다음에 입력받을 데이터가 있는지를 판단하는 메서드가 있어, 해당 메서드가 false가 될 때 까지 반복하여 입력을 처리하면 된다.

 

 

 


 

BufferedReader

 

BufferedReader은 앞서 말했듯 입력을 빠르게 받을 때 효율적이라고 하였다. 

 

이름에서 유추할 수 있듯, 버퍼를 사용하여 데이터를 읽을 때 일정량의 데이터를 한 번에 읽어서 메모리에 저장한다. 따라서 한 번에 많은 양의 데이터를 읽어와 버퍼에 저장하고, 그 버퍼에서 필요한 만큼 데이터를 읽어오기 때문에 시스템 호출을 줄여 성능을 향상시킬 수 있다. 

 

다만 사용하는 방법이 Scanner에 비해서 다소 복잡한 감이 많다.

 

 

 


BufferedReader 기본 작성

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.print("이름을 입력하세요: ");
        String name = br.readLine();
        System.out.println("이름: " + name);
    }
}

 

표준 입력으로 BufferedReader를 사용하는 가장 기본적인 방법이다.

1. BufferedReader는 예외를 처리하므로 사용하려면 IOException에 대한 예외 처리가 필요하다.

2. BufferedReader의 생성자 매개변수로는 표준 입력 객체인 InputStreamReader(System.in)을 넣어주어 표준 입력 객체로 사용할 수 있도록 한다.

3. readLine() : 한 줄을 입력받는 방법이다. 그렇지만 Scanner와 같이 공백으로 구분된 단어 단위로 입력을 받으려면 해당 메서드를 사용한 이후, String 메서드를 통해 일일이 공백 단위로 분리시켜 주거나 StringTokenizer 등을 이용해야 한다.

 

 

 

 

 


StringTokenizer : 토큰 단위 입력

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.print("이름과 나이를 입력하세요: ");

        StringTokenizer st = new StringTokenizer(br.readLine());
        String name = st.nextToken();
        int age = Integer.parseInt(st.nextToken());

        System.out.println("이름: " + name);
        System.out.println("나이: " + age);
    }
}
이름과 나이를 입력하세요: sjh 10
이름: sjh
나이: 10

 

공백으로 구분된 한 단어(Token) 단위로의 입력을 받도록 도와주는 StringTokenizer를 사용하면 입력을 단어 단위로 처리하기 쉬워진다. 위의 코드는 한 줄에 있는 이름과 나이를 공백 단위로 받아서 처리하는 코드를 작성한 것이다.

 

 

 

 


StringTokenizer : 토큰 단위와 줄 단위 읽어들이기

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int n = Integer.parseInt(st.nextToken());
        String[] names = new String[n];
        int[] ages = new int[n];

        System.out.println(n + "명의 이름과 나이를 입력하세요");
        for(int i = 0; i < n; i++){
            st = new StringTokenizer(br.readLine());
            names[i] = st.nextToken();
            ages[i] = Integer.parseInt(st.nextToken());
        }

        System.out.println(Arrays.toString(names));
        System.out.println(Arrays.toString(ages));
    }
}
3
3명의 이름과 나이를 입력하세요
sjh 10
kim 20
lee 30
[sjh, kim, lee]
[10, 20, 30]

 

다음 코드는 실제 코딩 테스트 문제의 입력으로 많이 사용될 법한 입력의 예시이다. N을 입력받은 후, N개의 이름과 나이의 쌍을 입력받는 코드를 작성한 것이다.

이 때 유의할 점은, 만약 라인 단위의 변화를 함께 고려해야 하는 경우, st = new StringTokenizer(br.readLine())을 통해 다음 줄을 읽어들여야 한다는 점이다.

 

 

 

 


EOF

import java.util.*;
import java.io.*;

public class Main{
    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String s = "";
        StringBuilder sb = new StringBuilder();
        while((s = br.readLine()) != null && !s.isEmpty()){
            StringTokenizer st = new StringTokenizer(s);
            int i = Integer.parseInt(st.nextToken());
            int j = Integer.parseInt(st.nextToken());
            sb.append(i+j).append("\n");
        }
        System.out.println(sb);
    }
}
10 20
20 30
30 40
40 50

30
50
70
90

 

마찬가지로 EOF를 처리하기 위해서 StringBuilder를 사용한 코드의 예시이다.

해당 코드의 반복문의 조건으로 String에 br.readLine()을 저장하며, 해당 문자열이 Null 혹은 Empty가 아닐 경우 데이터를 계속해서 읽어들이도록 하였다.

이 때 읽어들인 문자열은 반복문 내에서 StringTokenizer에 의해서 Token 단위로 사용 가능하도록 해 주었다.

 

 

 


PS 문제의 입력 패턴 정리

 

입력은 PS 문제, 코딩 테스트에서 계속해서 사용할 수 밖에 없다. 문제들에서 자주 보이는 입력 패턴들을 아래에 정리해 두었다. 

 

 

패턴1 : 단순 입력받기

 

입력

첫째 줄에 자연수 N과 M이 주어진다. (1 ≤ M ≤ N ≤ 8)

 

 

 

 

public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    int m = sc.nextInt();
	// ...
}

 

다음 문제와 같이 입력 사이즈가 그렇게 크지 않으면서 고정되어 있는 경우에는 사용하기 간편한 Scanner를 사용해도 좋다.

물론 BufferedReader가 익숙하다면 사용해도 상관 없다.

 

 

 


패턴2 : N을 입력받은 후 N개의 Element 입력받기

 

입력

첫째 줄에 집의 수 N(2 ≤ N ≤ 1,000)이 주어진다. 둘째 줄부터 N개의 줄에는 각 집을 빨강, 초록, 파랑으로 칠하는 비용이 1번 집부터 한 줄에 하나씩 주어진다. 집을 칠하는 비용은 1,000보다 작거나 같은 자연수이다.

 

 

public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    StringTokenizer st = new StringTokenizer(br.readLine());

    n = Integer.parseInt(st.nextToken());
    rgbs = new int[n][3];
    k = new int[n][3];
    for(int i = 0; i < n; i++){
        st = new StringTokenizer(br.readLine());
        rgbs[i][0] = Integer.parseInt(st.nextToken());
        rgbs[i][1] = Integer.parseInt(st.nextToken());
        rgbs[i][2] = Integer.parseInt(st.nextToken());
    }

}

 

N이 크다면 Scanner를 사용하는 것보다 BufferedReader를 사용하는 것이 좋다.

 

 

 


패턴3 : EOF까지 입력 받기

 

입력

입력을 여러 줄로 이루어져 있다. 각 줄에 N이 주어진다. 파일의 끝에서 입력을 멈춘다. N은 0보다 크거나 같고, 12보다 작거나 같은 정수이다.

 

 

public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    String line = "";
    StringBuilder sb = new StringBuilder();
    while ((line = br.readLine()) != null && !line.isEmpty()) {
        int n = Integer.parseInt(line);
        //...
    }
    br.close();
}

 

입력 크기를 예상할 수 없다면 BufferedReader를 사용하는 것이 좋다.

 

 

 


패턴4 : 특정 입력까지 계속 입력받기

 

입력

입력은 세 정수 a, b, c로 이루어져 있으며, 한 줄에 하나씩 주어진다. 입력의 마지막은 -1 -1 -1로 나타내며, 세 정수가 모두 -1인 경우는 입력의 마지막을 제외하면 없다.

 

 

 

public static void main(String[] args) throws IOException {
    StringBuilder sb = new StringBuilder();
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    StringTokenizer st;
    String s = "";
    while((s = br.readLine()) != null && !s.isEmpty()){
        st = new StringTokenizer(s);
        int a = Integer.parseInt(st.nextToken());
        int b = Integer.parseInt(st.nextToken());
        int c = Integer.parseInt(st.nextToken());
        if(a == -1 && b == -1 && c == -1){
            break;
        }
        sb.append(String.format("(%d, %d, %d)", a, b, c)).append("\n");
    }
    System.out.println(sb);

}

 

마찬가지로 입력 크기를 예상할 수 없다면 BufferedReader를 사용하는 것이 좋다.

반응형

BELATED ARTICLES

more