// // SwiftParser.swift // Padel Tournament // // Created by Razmig Sarkissian on 01/09/2023. // import Foundation typealias LineIterator = AsyncLineSequence.AsyncIterator struct Line: Identifiable { let id: UUID = UUID() let date: Date let source: URL let lineNumber: Int let rawValue: String let data: [String?] // func updatePlayer(player: Player) { // player.clubName = data[11] // player.ligue = data[9] // player.country = data[4] // player.license = data[5] // player.inscriptionRank = rank // player.currentRank = rank // player.tournamentCount = Int16(tournamentCount) // player.points = points ?? 0 // player.codeClub = data[10] // player.assimilation = assimilation // } var points: Double? { if let pointsValue { return Double(pointsValue.replacingOccurrences(of: ",", with: ".")) } return nil } var pointsValue: String? { data[6] ?? nil } var tournamentCountValue: String? { data[8] ?? nil } var tournamentCount: Int64 { if let tournamentCountValue { return Int64(tournamentCountValue) ?? 0 } return 0 } var rankValue: String? { data[1] ?? nil } var rank: Int { if let rankValue { return Int(rankValue) ?? 0 } return 0 } var assimilation: String? { data[7] } } struct CSVParser: AsyncSequence, AsyncIteratorProtocol { typealias Element = Line private let url: URL private var lineIterator: LineIterator private let seperator: Character private let quoteCharacter: Character = "\"" private var lineNumber = 0 private let date: Date let maleData: Bool init(url: URL, seperator: Character = ";") { self.date = url.dateFromPath self.url = url self.seperator = seperator self.lineIterator = url.lines.makeAsyncIterator() self.maleData = url.path().contains(SourceFile.messieurs.rawValue) } mutating func last() async throws -> Line? { var lastString: String? var currentString: String? var isOver: Bool = false while isOver == false { lastString = currentString currentString = try await lineIterator.next() if currentString == nil { isOver = true } } if let lastString { return Line( date: date, source: url, lineNumber: lineNumber, rawValue: lastString, data: split(line: lastString)) } return nil } mutating func next() async throws -> Line? { if let string = try await lineIterator.next() { defer { lineNumber += 1 } return Line( date: date, source: url, lineNumber: lineNumber, rawValue: string, data: split(line: string) ) } return nil } func makeAsyncIterator() -> CSVParser { return self } private func split(line: String) -> [String?] { var data = [String?]() var inQuote = false var currentString = "" for character in line { switch character { case quoteCharacter: inQuote = !inQuote continue case seperator: if !inQuote { data.append(currentString.isEmpty ? nil : currentString) currentString = "" continue } default: break } currentString.append(character) } data.append(currentString.isEmpty ? nil : currentString) return data } }