SwiftCSV

by swiftcsv

swiftcsv / SwiftCSV

CSV parser for Swift

459 Stars 137 Forks Last release: 7 months ago (0.5.6) MIT License 145 Commits 16 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:

SwiftCSV

Swift 5.0 Platform support Build Status Code coverage status CocoaPods Compatible Carthage compatible License MIT Reviewed by Hound

Simple CSV parsing for macOS, iOS, tvOS, and watchOS.

Usage

CSV content can be loaded using the

CSV
class:
import SwiftCSV

do { // As a string let csv: CSV = try CSV(string: "id,name,age\n1,Alice,18")

// With a custom delimiter character
let tsv: CSV = try CSV(string: "id\tname\tage\n1\tAlice\t18", delimiter: "\t")

// From a file (with errors)
let csvFile: CSV = try CSV(url: URL(fileURLWithPath: "path/to/users.csv"))

// From a file inside the app bundle, with a custom delimiter, errors, and custom encoding
let resource: CSV? = try CSV(
    name: "users", 
    extension: "tsv", 
    bundle: .main, 
    delimiter: "\t", 
    encoding: .utf8)

} catch parseError as CSVParseError { // Catch errors from parsing invalid formed CSV } catch { // Catch errors from trying to load files }

API

If you don't care about accessing named columns, you can set the

loadColumns
argument to
false
and the columns Dictionary will not be populated. This can increase performance in critical cases for lots of data.
class CSV {
    /// 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

/// 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

/// 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)

}

public enum CSVParseError: Error { case generic(message: String) case quotation(message: String) }

Reading Data

let csv = CSV(string: "id,name,age\n1,Alice,18\n2,Bob,19")
csv.header         //=> ["id", "name", "age"]
csv.namedRows      //=> [["id": "1", "name": "Alice", "age": "18"], ["id": "2", "name": "Bob", "age": "19"]]
csv.namedColumns   //=> ["id": ["1", "2"], "name": ["Alice", "Bob"], "age": ["18", "19"]]

The rows can also parsed and passed to a block on the fly, reducing the memory needed to store the whole lot in an array:

// Access each row as an array (array not guaranteed to be equal length to the header)
csv.enumerateAsArray { array in
    print(array.first)
}
// Access them as a dictionary
csv.enumerateAsDict { dict in
    print(dict["name"])
}

Installation

CocoaPods

pod "SwiftCSV"

Carthage

github "swiftcsv/SwiftCSV"

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.