낙's PushOff

[Swift 문법] readLine() 함수 본문

Swift 문법

[Swift 문법] readLine() 함수

유낙 2022. 11. 7. 21:05
백준 문제 풀이를 위한 기초!
입력을 읽어 들이는 역할을 수행하는 readLine() 함수에 대해 알아보자

정의

readLine(strippingNewline:)

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

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

분석

   readLine() 함수에 대한 애플 Documents의 간단한 설명과 정의는 위와 같다. 이해를 위해 다음과 같은 입력이 들어왔다고 가정해 보자.

// console input
// 1
// 8 2 Hello

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

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

간단하게 보자면, 들어온 콘솔 입력을 한 줄씩 한 줄씩 읽어서 String? 타입의 값으로 반환해주는 것이다. 그렇다면 어째서 다루기 불편하게 String? 타입으로 반환하는 걸까? 이 이유 역시 간단하다. 마지막 함수의 반환 값을 보면 알 수 있듯이,  EOF에 도달한 이후 readLine() 함수를 실행한다면 입력된 문자열이 없으므로 읽어올 값이 없기 때문에 nil을 반환함으로써 이러한 경우를 처리하기 위함이다.

 

활용

  여기까지 잘 이해되었다면, 이제 readLine() 함수를 이용해 이용해 입력 값을 처리하는 여러 방식들을 살펴보자. 이전 글에서 살펴본 print() 함수를 이용한 출력과 마찬가지로 콘솔 형태로 입력을 받는 백준 문제를 풀기 위해 아주 능숙하게 다루어야 하는 파트이다. 백준에서 입력받은 값은 대부분 배열에 넣어 처리하는 경우가 많다. 입력받은 값들을 하나의 배열에 정리하고 싶은 경우, 이를 처리하는 방식은 다음과 같이 나뉜다.

 

 

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


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

// example input
// 3
// 1
// 7
// 645

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

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

// inputs = [1, 7, 645]

 

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

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

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

// example input
// 17
// 60
// 24

var inputs = Array<Int>()

while let input = readLine() {		// readLine()의 반환값이 nil이 되는 경우 루프가 종료된다.
	inputs.append(input)	
}

// inputs = [17, 60, 24]

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

 

 

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


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

 

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

// example input
// 3 4 5 6

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

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

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

 

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

 

  참고로, 백준에서는 입력이 들어오는 것이 확실하므로 옵셔널 강제 해제 연산자 !를 애용하는 것이 좋다.
확실한 값을 굳이 옵셔널인 체로 값을 다루는 것은 비효율적이기 때문에, 오류에 대응해야 하는 실제 개발과정과 다르게 옵셔널 강제 해제 연산자 !를 자주 사용한다.

 

 

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

 

  위 예제와 같이 한자리 숫자인데 공백 없이 '3456'으로 입력된 경우, 아래와 같은 코드를 유용하게 사용할 수 있다.

var input = Array(readLine()!).map{Int($0)!}

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

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


결론

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

 

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

 

 

Reference

야곰 스위프트 프로그래밍 3판

애플 공식 문서

 

 

Apple Developer Documentation

 

developer.apple.com

'Swift 문법' 카테고리의 다른 글

[Swift 문법] print() 함수  (0) 2022.10.30