HCN DEV

Swift 표준입력 라이브러리

Swift 표준입력 라이브러리 feature image

요즘 알고리즘 문제 사이트에서 문제를 푸는데, Swift로 답안을 제출할 수 있어서 종종 Swift로 답안을 작성합니다. 다만, 대부분 알고리즘 문제들은 콘솔에서 입력을 받기 때문에 콘솔의 입력을 다루는 메소드를 작성해야 합니다. 그런데.. Swift에서는 아직까지 지원하는 메소드가 readLine()밖에 없어서 Int형 데이터, Double형 데이터를 별도로 캐스팅해주어야 하고, 개별 String에 접근하려면 라인 전체를 읽고, 이를 잘라서 접근해야만 했습니다.

또한… Optional은 코드의 안전성을 높여주긴 하지만, 일반적으로 표준 입력을 받는 알고리즘 문제들은 값이 보장되어 있는 경우가 대부분이므로 값을 unwrap하는 일도 상당히 성가십니다. 그래서 이제까지는 문제별로 코드를 작성했었는데, 인내심의 한계에 도달해서 직접 input을 받는 Struct를 제작하였습니다. 코드는 아래와 같습니다.

소스 코드

// Swift 3.1
import Foundation

struct ReadInput {

    private var currentIndex: Int = 0
    private var inputArray: [String] = []

    // 데이터를 배열로 변환
    public mutating func readLineToArray() -> [String] {

        guard let result = readLine() else {
            return []
        }

        return result.components(separatedBy: " ")
    }

    // 띄어쓰기 단위로 String 읽기
    public mutating func read() -> String {
        if inputArray.count == 0 {
            inputArray = self.readLineToArray()
        }
        let result = inputArray[inputArray.index(after: currentIndex-1)]
        currentIndex += 1

        if currentIndex == inputArray.count {
            self.inputArray.removeAll()
            self.currentIndex = 0
        }

        return result
    }

    // Int 데이터 읽기
    public mutating func readInt() -> Int {
        guard let result = Int(self.read()) else {
            fatalError("Int형 데이터가 아닙니다.")
        }

        return result
    }

    // Double 데이터 읽기
    public mutating func readDouble() -> Double {
        guard let result = Double(self.read()) else {
            fatalError("Double형 데이터가 아닙니다.")
        }

        return result
    }
}

코드를 사용하기 위해서는 Foundation을 import해야 합니다. 제공하는 메소드는 크게 4가지입니다. 메소드들은 자바의 next(), nextInt() 등의 기능과 비슷합니다. read()는 단일 String을 읽고, readInt(), readDouble()은 숫자를, readLineToArray()는 읽은 라인을 배열로 변환한 데이터를 리턴합니다.

사용법

사용법은 매우 간단합니다.

var ri = ReadInput()

let str1 = ri.read() // String 리턴
let num1 = ri.readInt() // Int 리턴
let num2 = ri.readDouble() // Int 리턴
let line = ri.readLineToArray() // [String] 배열 리턴

자바에서 Scanner 인스턴스를 만들듯이, ReadInput 인스턴스를 만들고 필요한 메소드를 사용하면 됩니다.