You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

133 lines
5.3 KiB

//
// CSV.swift
// SwiftCSV
//
// Created by Naoto Kaneko on 2/18/16.
// Copyright © 2016 Naoto Kaneko. All rights reserved.
//
import Foundation
public protocol View {
associatedtype Rows
associatedtype Columns
var rows: Rows { get }
var columns: Columns { get }
init(header: [String], text: String, delimiter: Character, limitTo: Int?, loadColumns: Bool) throws
}
open class CSV {
static public let comma: Character = ","
public let header: [String]
lazy var _namedView: NamedView = {
return try! NamedView(
header: self.header,
text: self.text,
delimiter: self.delimiter,
loadColumns: self.loadColumns)
}()
lazy var _enumeratedView: EnumeratedView = {
return try! EnumeratedView(
header: self.header,
text: self.text,
delimiter: self.delimiter,
loadColumns: self.loadColumns)
}()
var text: String
var delimiter: Character
let loadColumns: Bool
/// List of dictionaries that contains the CSV data
public var namedRows: [[String : String]] {
return _namedView.rows
}
/// Dictionary of header name to list of values in that column
/// Will not be loaded if loadColumns in init is false
public var namedColumns: [String : [String]] {
return _namedView.columns
}
/// Collection of column fields that contain the CSV data
public var enumeratedRows: [[String]] {
return _enumeratedView.rows
}
/// Collection of columns with metadata.
/// Will not be loaded if loadColumns in init is false
public var enumeratedColumns: [EnumeratedView.Column] {
return _enumeratedView.columns
}
@available(*, unavailable, renamed: "namedRows")
public var rows: [[String : String]] {
return namedRows
}
@available(*, unavailable, renamed: "namedColumns")
public var columns: [String : [String]] {
return namedColumns
}
/// Load CSV data from a string.
///
/// - parameter string: CSV contents to parse.
/// - parameter delimiter: Character used to separate row and header fields (default is ',')
/// - parameter loadColumns: Whether to populate the `columns` dictionary (default is `true`)
/// - throws: `CSVParseError` when parsing `string` fails.
public init(string: String, delimiter: Character = comma, loadColumns: Bool = true) throws {
self.text = string
self.delimiter = delimiter
self.loadColumns = loadColumns
self.header = try Parser.array(text: string, delimiter: delimiter, limitTo: 1).first ?? []
}
@available(*, deprecated, message: "Use init(url:delimiter:encoding:loadColumns:) instead of this path-based approach. Also, calling the parameter `name` instead of `path` was a mistake.")
public convenience init(name: String, delimiter: Character = comma, encoding: String.Encoding = .utf8, loadColumns: Bool = true) throws {
try self.init(url: URL(fileURLWithPath: name), delimiter: delimiter, encoding: encoding, loadColumns: loadColumns)
}
/// Load a CSV file as a named resource from `bundle`.
///
/// - parameter name: Name of the file resource inside `bundle`.
/// - parameter ext: File extension of the resource; use `nil` to load the first file matching the name (default is `nil`)
/// - parameter bundle: `Bundle` to use for resource lookup (default is `.main`)
/// - parameter delimiter: Character used to separate row and header fields (default is ',')
/// - parameter encoding: encoding used to read file (default is `.utf8`)
/// - parameter loadColumns: Whether to populate the columns dictionary (default is `true`)
/// - throws: `CSVParseError` when parsing the contents of the resource fails, or file loading errors.
/// - returns: `nil` if the resource could not be found
public convenience init?(name: String, extension ext: String? = nil, bundle: Bundle = .main, delimiter: Character = comma, encoding: String.Encoding = .utf8, loadColumns: Bool = true) throws {
guard let url = bundle.url(forResource: name, withExtension: ext) else {
return nil
}
try self.init(url: url, delimiter: delimiter, encoding: encoding, loadColumns: loadColumns)
}
/// Load a CSV file from `url`.
///
/// - parameter url: URL of the file (will be passed to `String(contentsOfURL:encoding:)` to load)
/// - parameter delimiter: Character used to separate row and header fields (default is ',')
/// - parameter encoding: Character encoding to read file (default is `.utf8`)
/// - parameter loadColumns: Whether to populate the columns dictionary (default is `true`)
/// - throws: `CSVParseError` when parsing the contents of `url` fails, or file loading errors.
public convenience init(url: URL, delimiter: Character = comma, encoding: String.Encoding = .utf8, loadColumns: Bool = true) throws {
let contents = try String(contentsOf: url, encoding: encoding)
try self.init(string: contents, delimiter: delimiter, loadColumns: loadColumns)
}
/// Turn the CSV data into NSData using a given encoding
open func dataUsingEncoding(_ encoding: String.Encoding) -> Data? {
return description.data(using: encoding)
}
}