// // Foundation+Extensions.swift // KissMeConsole // // Created by ened-book-m1 on 2023/05/26. // import Foundation import KissMe extension String { func maxSpace(_ length: Int) -> String { let count = unicodeScalars.reduce(0) { $0 + ($1.value >= 0x80 ? 2: 1) } if count < length { return appending(String(repeating: " ", count: length - count)) } return self } func maxSpace(_ length: Int, digitBy: Int) -> String { guard let number = Int(self) else { return self } // Add comma let formatter = NumberFormatter() formatter.numberStyle = .decimal guard let str = formatter.string(from: NSNumber(value: number)) else { return self } // Add space let count = str.count if (count + count / 3) <= length { return str.appending(String(repeating: " ", count: length - count)) } return self } } extension Date { public var yyyyMMdd_split: (year: Int, month: Int, day: Int)? { let sets: Set = [.year, .month, .day, .hour, .minute, .second] let components = Calendar.current.dateComponents(sets, from: self) guard let year = components.year, let month = components.month, let day = components.day else { return nil } return (year, month, day) } public var HHmmss_split: (hour: Int, minute: Int, second: Int)? { let sets: Set = [.year, .month, .day, .hour, .minute, .second] let components = Calendar.current.dateComponents(sets, from: self) guard let hour = components.hour, let minute = components.minute, let second = components.second else { return nil } return (hour, minute, second) } public func changing(hour: Int, min: Int, sec: Int, timeZone: String = "KST") -> Date? { let sets: Set = [.year, .month, .day, .hour, .minute, .second] var components = Calendar.current.dateComponents(sets, from: self) components.timeZone = TimeZone(abbreviation: timeZone) components.hour = hour components.minute = min components.second = sec return Calendar.current.date(from: components) } public mutating func change(hour: Int, min: Int, sec: Int, timeZone: String = "KST") { if let newDate = changing(hour: hour, min: min, sec: sec, timeZone: timeZone) { self = newDate } } public func changing(year: Int, month: Int, day: Int, timeZone: String = "KST") -> Date? { let sets: Set = [.year, .month, .day, .hour, .minute, .second] var components = Calendar.current.dateComponents(sets, from: self) components.timeZone = TimeZone(abbreviation: timeZone) components.year = year components.month = month components.day = day return Calendar.current.date(from: components) } public mutating func change(year: Int, month: Int, day: Int, timeZone: String = "KST") { if let newDate = changing(year: year, month: month, day: day, timeZone: timeZone) { self = newDate } } } extension Array where Element: PropertyIterable { func writeCsv(toFile: URL) throws { var stringCsv = "" for item in self { let all = try item.allProperties() if stringCsv.isEmpty { let header = all.map{ $0.0 }.joined(separator: ",").appending("\n") stringCsv.append(header) } let values = all.map{ ($0.1 as? String) ?? "" }.joined(separator: ",").appending("\n") stringCsv.append(values) } try stringCsv.write(toFile: toFile.path, atomically: true, encoding: .utf8) } static func readCsv(fromFile: URL, verifyHeader: Bool = true) throws -> [Element] where Element: ArrayDecodable { let stringCsv = try String(contentsOfFile: fromFile.path, encoding: .utf8) let items = stringCsv.split(separator: "\n") guard items.count > 0 else { return [] } var headerItems = [String]() var elements = [Element]() for (index, item) in items.enumerated() { if index == 0 { headerItems = item.split(separator: ",").map { String($0) } continue } let array = item.split(separator: ",").map { String($0) } let element = try Element(array: array) if index == 1, verifyHeader { // Validate property with header let properties = try element.allProperties() for (label, _) in properties { if false == headerItems.contains(where: { $0 == label }) { throw GeneralError.headerNoFiendName(label) } } } elements.append(element) } return elements } }