Created
February 12, 2019 07:02
-
-
Save myssun0325/a98c50f1b43f5ec1007b9e2f651d4236 to your computer and use it in GitHub Desktop.
단위변환기
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// main.swift | |
// UnitConverter | |
// | |
// Created by moon on 2018. 3. 5.. | |
// Copyright © 2018년 moon. All rights reserved. | |
// | |
import Foundation | |
enum Unit { | |
case length | |
case weight | |
} | |
enum WeightUnit: String { | |
case g | |
case kg | |
case oz | |
case lb | |
} | |
enum LengthUnit: String { | |
case cm | |
case m | |
case inch | |
case yard | |
} | |
// DTO 연습 | |
struct WordDTO { | |
var value: String | |
var unit: String | |
var unitToConvert: String? | |
} | |
struct Spliter { | |
private let customDigits = CharacterSet(charactersIn: "01234567890.") | |
func split(_ input: String) -> WordDTO { | |
let words: [String] = makeWordsOf(input) | |
let firstWord: String = extractFirstWordFrom(words) | |
let secondWord: String? = extractSecondWordFrom(words) | |
let valueWord: String = extractUnitFrom(firstWord, extractValue: true) | |
let unitWord: String = extractUnitFrom(firstWord) | |
var output = WordDTO(value: valueWord, unit: unitWord, unitToConvert: nil) | |
if let unitToConvert = secondWord { | |
output.unitToConvert = unitToConvert | |
} | |
return output | |
} | |
private func makeWordsOf(_ input: String) -> [String] { | |
let words = input.split(separator: " ") | |
return words.map{ String($0) } | |
} | |
private func extractFirstWordFrom(_ words: [String]) -> String { | |
return words[0] | |
} | |
private func extractSecondWordFrom(_ words: [String]) -> String? { | |
if words.count == 2 { | |
return words[words.count - 1] | |
} else { | |
return nil | |
} | |
} | |
private func extractUnitFrom(_ word: String, extractValue: Bool = false) -> String { | |
var value = String() | |
var unit = String() | |
for scalar in word.unicodeScalars { | |
if isDigit(scalar) { | |
value.append(Character(scalar)) | |
} else { | |
unit.append(Character(scalar)) | |
} | |
} | |
if extractValue { | |
return value | |
} else { | |
return unit | |
} | |
} | |
/// Check whether a given character is a digit or not | |
private func isDigit(_ element: Unicode.Scalar) -> Bool { | |
if self.customDigits.contains(element) { | |
return true | |
} else { | |
return false | |
} | |
} | |
} | |
struct Converter { | |
// 변환할 단위를 입력하지 않았을 경우 Default로 설정된 값으로 변환하기 위한 multiplier | |
private let multiplierToDefault: [String:Double] = ["cm" : 0.01, | |
"m" : 100, | |
"inch" : 1, | |
"yard" : 0.9144, | |
"g" : 0.001, | |
"kg" : 1000, | |
"oz" : 1, | |
"lb" : 1] | |
// 변환할 단위를 입력하지 않았을 경우 Default로 설정된 단위로 변환 | |
private let defaultUnit: [String:String] = ["cm" : "m", | |
"m" : "cm", | |
"yard" : "m", | |
"g" : "kg", | |
"kg" : "g"] | |
// 길이단위의 기준값은 cm이므로 기준값으로 변환하기 위한 multiplier | |
private let multiplierToCentimeter: [String:Double] = ["cm" : 1, | |
"m" : 100, | |
"inch" : 2.54, | |
"yard" : 91.44] | |
// 무게단위의 기준값은 kg이므로 기준값으로 변환히기 위한 multiplier | |
private let multiplierToKg: [String:Double] = ["g" : 0.001, | |
"kg" : 1, | |
"oz" : 0.0283495, | |
"lb" : 0.453592] | |
func convert(input: WordDTO) -> WordDTO? { | |
// 첫번째 문자열이 숫자타입(Double)로 변환되는지 체크 | |
guard let value = Double(input.value) else { | |
print("입력된 숫자가 잘못되었습니다.") | |
return nil | |
} | |
// 입력한 단위를 지원하는지 체크 | |
// 여기서 unit은 변환할 단위를 체크하기 위해 사용된다. | |
// 이를 가지고 입력한 단위와 변환할 단위 사이의 변환을 지원하는지 체크한다.(ex: cm -> kg (x)) | |
guard let unit: Unit = check(unit: input.unit) else { | |
print("입력한 단위는 지원하지 않습니다.") | |
return nil | |
} | |
// 검사가 끝났으면 보장된 입력된 값과 단위를 DTO에 담는다. | |
var output = WordDTO(value: input.value, unit: input.unit, unitToConvert: nil) | |
// 만약 변환할 단위를 입력했다면 | |
if let unitToConvert = input.unitToConvert { | |
// 변환하고 싶은 단위를 지원하는지 체크 후 | |
guard let unitToConvert: String = checkUnit(from: unit, to: unitToConvert) else { | |
print("변환할 단위를 지원하지 않습니다.") | |
return nil | |
} | |
// DTO에 넣는다. | |
output.unitToConvert = unitToConvert | |
} | |
// 모든 체크가 끝났다면 변환을 시작한다. | |
// 변환할 단위를 입력했을 경우 | |
if let unitToConvert = output.unitToConvert { | |
// 값 변환 | |
switch unit { | |
case .length: | |
output.value = convertLength(value: value, unit: input.unit, unitToConvert: unitToConvert) | |
case .weight: | |
output.value = convertWeight(value: value, unit: input.unit, unitToConvert: unitToConvert) | |
} | |
// 단위 변환 | |
output.unit = unitToConvert | |
} else { | |
// 변환할 단위를 입력 안했을 경우 | |
// 값 변환 | |
output.value = convertToDefault(value: value, unit: output.unit) | |
// 단위 변환 | |
if let unitToConvert = self.defaultUnit[output.unit] { | |
output.unit = unitToConvert | |
} | |
} | |
return output | |
} | |
//MARK: 유효성 검사 | |
private func check(unit: String) -> Unit? { | |
if let _ = LengthUnit(rawValue: unit) { | |
return Unit.length | |
} else if let _ = WeightUnit(rawValue: unit) { | |
return Unit.weight | |
} else { | |
return nil | |
} | |
} | |
// 첫번째 입력단위가 무게면 지원하는 무게단위인지를 체크, 길이면 지원하는 길이단위인지를 체크 | |
private func checkUnit(from unit: Unit, to unitToConvert: String) -> String? { | |
// 첫번재 단위를 체크해서 변환할 단위가 첫번째 단위로부터 변환가능한 단위인지 체크 | |
switch unit { | |
case .length: | |
return LengthUnit(rawValue: unitToConvert)?.rawValue | |
case .weight: | |
return WeightUnit(rawValue: unitToConvert)?.rawValue | |
} | |
} | |
// 변환할 단위 없을 시 기본변환 | |
private func convertToDefault(value: Double, unit: String) -> String { | |
var result = value | |
if let multiplier = self.multiplierToDefault[unit] { | |
result = value * multiplier | |
} | |
return String(result) | |
} | |
// 길이단위 변환 | |
private func convertLength(value: Double, unit: String, unitToConvert: String) -> String { | |
var result = value | |
if let multiplierToCentimeter = self.multiplierToCentimeter[unit], | |
let centimeterToUnit = self.multiplierToCentimeter[unitToConvert] { | |
result = value * multiplierToCentimeter * centimeterToUnit | |
} | |
return String(result) | |
} | |
// 무게단위 변환 | |
private func convertWeight(value: Double, unit: String, unitToConvert: String) -> String { | |
var result = value | |
if let multiplierToKg = self.multiplierToKg[unit], let kgToUnit = self.multiplierToKg[unitToConvert] { | |
result = value * multiplierToKg * kgToUnit | |
} | |
return String(result) | |
} | |
} | |
struct Printer { | |
func printLength(_ input: WordDTO) { | |
print("Result: \(input.value)\(input.unit)") | |
print("=========================================================") | |
} | |
} | |
struct Getter { | |
func getLength() -> String { | |
print("무게단위: g, kg, oz, lb 길이단위: cm, m, inch, yard") | |
print("단위값과 변환할 단위를 입력해주세요.") | |
print("('q' 또는 'quit' 입력시 프로그램 종료)") | |
var length = String() | |
while true { | |
print("입력: ", terminator: "") | |
guard let input = readLine() else { | |
print("Error: input is nil") | |
continue | |
} | |
// 입력이 빈칸일 경우와 스페이스로 시작할 경우 | |
if input.isEmpty || input.hasPrefix(" ") { | |
print("Error: input is empty") | |
continue | |
} | |
if input == "q" || input == "quit" { | |
length = "q" | |
exit(0) | |
} | |
length = input | |
break | |
} | |
return length | |
} | |
} | |
// MARK: Main | |
func main() { | |
// 루프를 돌면서 아래의 인스턴스들이 생성, 소멸을 반복하여 순서를 위로 올렸습니다. | |
let getter = Getter() | |
let spliter = Spliter() | |
let converter = Converter() | |
let printer = Printer() | |
while true { | |
let input = getter.getLength() | |
let splitedInput: WordDTO = spliter.split(input) | |
let converted: WordDTO? = converter.convert(input: splitedInput) | |
if let result = converted { | |
printer.printLength(result) | |
} | |
} | |
} | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment