mirror of https://github.com/oxen-io/session-ios
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
112 lines
3.6 KiB
Swift
112 lines
3.6 KiB
Swift
5 years ago
|
//
|
||
|
// Parser.swift
|
||
|
// SwiftCSV
|
||
|
//
|
||
|
// Created by Will Richardson on 13/04/16.
|
||
|
// Copyright © 2016 Naoto Kaneko. All rights reserved.
|
||
|
//
|
||
|
|
||
|
extension CSV {
|
||
|
/// Parse the file and call a block on each row, passing it in as a list of fields
|
||
|
/// limitTo will limit the result to a certain number of lines
|
||
|
public func enumerateAsArray(limitTo: Int? = nil, startAt: Int = 0, _ block: @escaping ([String]) -> ()) throws {
|
||
|
|
||
|
try Parser.enumerateAsArray(text: self.text, delimiter: self.delimiter, limitTo: limitTo, startAt: startAt, block: block)
|
||
|
}
|
||
|
|
||
|
public func enumerateAsDict(_ block: @escaping ([String : String]) -> ()) throws {
|
||
|
|
||
|
try Parser.enumerateAsDict(header: self.header, content: self.text, delimiter: self.delimiter, block: block)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
enum Parser {
|
||
|
|
||
|
static func array(text: String, delimiter: Character, limitTo: Int? = nil, startAt: Int = 0) throws -> [[String]] {
|
||
|
|
||
|
var rows = [[String]]()
|
||
|
|
||
|
try enumerateAsArray(text: text, delimiter: delimiter) { row in
|
||
|
rows.append(row)
|
||
|
}
|
||
|
|
||
|
return rows
|
||
|
}
|
||
|
|
||
|
/// Parse the text and call a block on each row, passing it in as a list of fields.
|
||
|
///
|
||
|
/// - parameter text: Text to parse.
|
||
|
/// - parameter delimiter: Character to split row and header fields by (default is ',')
|
||
|
/// - parameter limitTo: If set to non-nil value, enumeration stops
|
||
|
/// at the row with index `limitTo` (or on end-of-text, whichever is earlier.
|
||
|
/// - parameter startAt: Offset of rows to ignore before invoking `block` for the first time. Default is 0.
|
||
|
/// - parameter block: Callback invoked for every parsed row between `startAt` and `limitTo` in `text`.
|
||
|
static func enumerateAsArray(text: String, delimiter: Character, limitTo: Int? = nil, startAt: Int = 0, block: @escaping ([String]) -> ()) throws {
|
||
|
var currentIndex = text.startIndex
|
||
|
let endIndex = text.endIndex
|
||
|
|
||
|
var fields = [String]()
|
||
|
var field = ""
|
||
|
|
||
|
var count = 0
|
||
|
|
||
|
func finishRow() {
|
||
|
fields.append(String(field))
|
||
|
if count >= startAt {
|
||
|
block(fields)
|
||
|
}
|
||
|
count += 1
|
||
|
fields = [String]()
|
||
|
field = ""
|
||
|
}
|
||
|
|
||
|
var state: ParsingState = ParsingState(
|
||
|
delimiter: delimiter,
|
||
|
finishRow: finishRow,
|
||
|
appendChar: { field.append($0) },
|
||
|
finishField: {
|
||
|
fields.append(field)
|
||
|
field = ""
|
||
|
})
|
||
|
|
||
|
func limitReached(_ count: Int) -> Bool {
|
||
|
|
||
|
guard let limitTo = limitTo,
|
||
|
count >= limitTo
|
||
|
else { return false }
|
||
|
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
while currentIndex < endIndex {
|
||
|
let char = text[currentIndex]
|
||
|
|
||
|
try state.change(char)
|
||
|
|
||
|
if limitReached(count) {
|
||
|
break
|
||
|
}
|
||
|
|
||
|
currentIndex = text.index(after: currentIndex)
|
||
|
}
|
||
|
|
||
|
if !fields.isEmpty || !field.isEmpty || limitReached(count) {
|
||
|
fields.append(field)
|
||
|
block(fields)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static func enumerateAsDict(header: [String], content: String, delimiter: Character, limitTo: Int? = nil, block: @escaping ([String : String]) -> ()) throws {
|
||
|
|
||
|
let enumeratedHeader = header.enumerated()
|
||
|
|
||
|
try enumerateAsArray(text: content, delimiter: delimiter, startAt: 1) { fields in
|
||
|
var dict = [String: String]()
|
||
|
for (index, head) in enumeratedHeader {
|
||
|
dict[head] = index < fields.count ? fields[index] : ""
|
||
|
}
|
||
|
block(dict)
|
||
|
}
|
||
|
}
|
||
|
}
|