session-ios/Session/Dependencies/SwiftCSV/ParsingState.swift

107 lines
3.2 KiB
Swift

//
// ParsingState.swift
// SwiftCSV
//
// Created by Christian Tietze on 25/10/16.
// Copyright © 2016 Naoto Kaneko. All rights reserved.
//
public enum CSVParseError: Error {
case generic(message: String)
case quotation(message: String)
}
/// State machine of parsing CSV contents character by character.
struct ParsingState {
private(set) var atStart = true
private(set) var parsingField = false
private(set) var parsingQuotes = false
private(set) var innerQuotes = false
let delimiter: Character
let finishRow: () -> Void
let appendChar: (Character) -> Void
let finishField: () -> Void
init(delimiter: Character,
finishRow: @escaping () -> Void,
appendChar: @escaping (Character) -> Void,
finishField: @escaping () -> Void) {
self.delimiter = delimiter
self.finishRow = finishRow
self.appendChar = appendChar
self.finishField = finishField
}
mutating func change(_ char: Character) throws {
if atStart {
if char == "\"" {
atStart = false
parsingQuotes = true
} else if char == delimiter {
finishField()
} else if char.isNewline {
finishRow()
} else {
parsingField = true
atStart = false
appendChar(char)
}
} else if parsingField {
if innerQuotes {
if char == "\"" {
appendChar(char)
innerQuotes = false
} else {
throw CSVParseError.quotation(message: "Can't have non-quote here: \(char)")
}
} else {
if char == "\"" {
innerQuotes = true
} else if char == delimiter {
atStart = true
parsingField = false
innerQuotes = false
finishField()
} else if char.isNewline {
atStart = true
parsingField = false
innerQuotes = false
finishRow()
} else {
appendChar(char)
}
}
} else if parsingQuotes {
if innerQuotes {
if char == "\"" {
appendChar(char)
innerQuotes = false
} else if char == delimiter {
atStart = true
parsingField = false
innerQuotes = false
finishField()
} else if char.isNewline {
atStart = true
parsingQuotes = false
innerQuotes = false
finishRow()
} else {
throw CSVParseError.quotation(message: "Can't have non-quote here: \(char)")
}
} else {
if char == "\"" {
innerQuotes = true
} else {
appendChar(char)
}
}
} else {
throw CSVParseError.generic(message: "me_irl")
}
}
}