Skip to content

Instantly share code, notes, and snippets.

@myssun0325
Created February 12, 2019 07:02
Show Gist options
  • Save myssun0325/a98c50f1b43f5ec1007b9e2f651d4236 to your computer and use it in GitHub Desktop.
Save myssun0325/a98c50f1b43f5ec1007b9e2f651d4236 to your computer and use it in GitHub Desktop.
단위변환기
//
// 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