[Swift 문법] readLine() 함수 (백준 PS를 위한 기본)

Nak·2023년 4월 30일
1
post-thumbnail

readLine()

백준 문제 풀이를 위한 기초!
입력을 읽어들이는 역할을 수행하는 readLine() 함수에 대해 알아보자

정의

readLine() 함수에 대한 애플 Documents의 간단한 설명과 정의는 아래와 같다.

readLine(strippingNewline:)
표준 입력에서 현재 줄의 끝 또는 EOF(End of File)에 도달할 때까지 읽은 문자열을 반환합니다.

func readline(strippingNewline: Bool = true) -> String?

분석

이해를 위해 다음과 같은 입력이 들어왔다고 가정해보자.

입력

1
8 2 Hello

이때 readLine() 함수를 세번 실행하면 반환값은 다음과 같다.

결과

readLine()      // Optional("1")
readLine()      // Optional("8 2 Hello")
readLine()      // nil

간단하게 보자면, 들어온 콘솔 입력을 한 줄씩 한 줄씩 읽어서 String? 타입의 값으로 반환해준다. 그렇다면 어째서 다루기 불편하게 String? 타입으로 반환하는 걸까?

그 이유 역시 간단하다. 마지막 readLine()의 반환 값을 보면 알 수 있듯이, EOF에 도달한 이후 readLine() 함수를 실행한다면 입력된 문자열이 없으므로 nil을 반환함으로써 이러한 경우를 처리하기 위함이다.


활용

여기까지 잘 이해되었다면, readLine() 함수를 이용해 입력 값을 처리하는 여러 방식들을 살펴보자. 백준 문제를 풀기 위해 제대로 알고 넘어가는 것이 좋다.

백준에서 입력받은 값은 대부분 배열에 넣어 처리하는 경우가 많다. 하나의 배열에 넣어 정리하고 싶은 경우, 이를 처리하는 방식은 다음과 같이 나뉜다.

1. 줄 바꿈을 통해 입력이 구분된 경우

readLine() 함수는 콘솔 입력을 통해 한 줄씩 읽어 들여 반환하므로, 입력이 들어오는 만큼 for문이나 while문을 이용해 반복 실행해주면 된다. 들어올 입력의 개수가 첫 번째 줄에 입력된 경우, 다음과 같이 처리할 수 있다.

입력

3   // 입력의 개수
1
7
645

결과

let N = Int(readLine()!)!     // 입력의 갯수 N
var inputs: [Int] = []        // 입력이 정리되어 들어갈 빈 배열

for _ in 0..<N {
	inputs.append(Int(readLine()!)!)
}

// inputs = [1, 7, 645]

만일 입력의 갯수를 모르는 경우는 어떻게 해야 할까?

readLine() 함수가 입력이 없는 경우, 즉 EOF 이후 실행된 경우 nil을 반환하는 것을 활용하면 된다. 이를 이용하면 EOF를 자체적으로 감지하고 읽어 들이는 것을 제때 중지할 수 있다.

입력의 개수 N이 첫째줄에 주어지지 않은 채, 입력의 개수가 모르는 채로 입력이 들어오는 경우, 다음과 같이 처리할 수 있다.

입력

17
60
24

결과

var inputs: [Int] = []        // 입력이 정리되어 들어갈 빈 배열

while let input = readLine() {
	inputs.append(input)
}

// inputs = [17, 60, 24]

백준 문제를 풀다 보면 종종 입력의 개수를 제공하지 않는 경우가 있으므로 잘 기억해두었다 필요할 때 사용하도록 하자! 또한, 특정한 값으로 EOF를 알리는 경우도 있는데, 이 때도 역시 while문을 이용해 비슷한 방식으로 처리해주면 된다.

2. 공백을 통해 입력이 구분된 경우

'3 4 5 6'과 같이 여러 입력값이 공백을 통해 구분되는 경우, readLine()은 전체를 한 번에 읽어 들이기 때문에 이를 배열로 처리해주는 과정이 필요하다.

String? 타입으로 반환하는 것을 생각하면 아래와 같은 코드를 사용해 간단하게 처리할 수 있다.

입력

3 4 5 6

결과

var inputs = readLine()!.split{$0 == " "}.map{Int(String($0))!}

// inputs = [3, 4, 5, 6]

String? 타입의 반환을 옵셔널 강제 해제 연산자 !를 통해 String 타입으로 해제한 뒤, split(seperator:) 메소드를 통해 공백마다 값을 분리해준다. (여기서는 후행 클로져를 사용하였다.) 이렇게 분리된 값은 Substring 타입으로 배열에 정리되며, 이를 우리가 사용하고자 하는 타입으로 map 함수를 통해 변환해주면 끝이 난다.

지금은 조금 어색하겠지만, 알고리즘 문제 해결을 위한 것이므로 간결하고 빠른 코드 작성을 위해 이같이 작성해주는 것이 좋다.

참고로, 백준 문제를 풀 때는 입력이 들어오는 것이 확실하므로 옵셔널 강제 해제 연산자 !를 애용하는 것이 좋다.
확실한 값을 굳이 옵셔널인 채로 다룰 필요가 없기 때문이다. 실제 개발에서는 오류처리를 위해 옵셔널 강제 해제 연산자를 잘 사용하지 않지만, 알고리즘 풀이에 한해서는 편하게 쓰자.

3. 공백 없이 입력이 구분된 경우 (각 입력이 Character 하나인 경우)

앞서 살펴본 예와 같이 한자리 숫자의 입력인데, 이번에는 공백없이 '3456'과 같이 입력된 경우, 아래와 같은 코드를 유용하게 사용할 수 있다

결과

var inputs = ArraY(readLine()!).map{ Int($0) }

// inputs = [3, 4, 5, 6]

String은 Character의 모임이므로, 이를 Array 초기화 메소드에 인자로 넣으면 ["3", "4", "5", "6"]과 같이 [Character] 타입의 배열을 얻을 수 있다. 역시 이를 원하는 타입으로 가공하기 위해 map을 사용했다.


결론

백준 문제를 풀며 다양한 방식의 입력을 접하게 될 텐데, 매 경우마다 해결 방법을 외워두기보다는 readLine() 함수 자체에 대해 잘 이해하고 있다면, 자연스럽게 해결방법을 얻을 수 있으리라 생각한다.

readLine() 함수는 한 줄씩 읽어 들이고, 그 반환 타입은 Sting? 이라는 점. 꼭꼭 기억하자!!



Reference

야곰 스위프트 프로그래밍 3판 (Swift 5)
애플 공식 문서

profile
자유로운,

0개의 댓글