Taking a string containing a csv file and split it into records (aka lines) containing fields of data (aka Array of SubStrings)

Overview

Swift .csv parser

Taking a string containing a csv file and split it into records (aka lines) containing fields of data (aka Array of SubStrings). Parsing the contents of the fields into "proper" data types like Int, Float, Date, … should be done in an additional step, which is outside of the scope of this parser. Especially there is no check whether all fields in the same row can be converted into a valid type.

Spec

The parsing is done adhering to https://github.com/parsecsv/csv-spec. In some cases this parser is a little more generous, especially in handling wrongly quoted fields.

A parsing error is reported when the number of fields is not identical for all lines or in some unrecoverable cases of improperly quoted fields. The parsing is not stopped by an error.

Usage

The logic of the parser is in /CSV Import/ParseCSV.swift. The rest of this repository is for quickly testing in an Xcode project.

  1. Read file and convert into String.
  2. Initialize a Struct copying the file String:
let csvFile = CSVFile(file: rawFile, fieldSeparator: ";", tryMaxLines: 5)
  1. You get a struct like this filled with the data:
struct CSVFile {
  let file: String
  var lines: Array<LineOfFields>
  var fieldSeparator: Character // Usually , or ; -- to separate fields from each other
  var errorFree: Bool = true
  init(file: String, fieldSeparator: Character = ",", tryMaxLines maxLines: Int? = nil) {
    self.file = file
    self.fieldSeparator = fieldSeparator
    self.lines = []
    self.parse(maxLines)
}
  
struct LineOfFields: Hashable, Identifiable {
    var fields: Array<Substring>
    let id = UUID()
}

If tryMaxLines is set to nil the file is parsed until end of file is hit. If it is set to an Int the parsing stops after finding this number of lines. This can be handy if you can't be certain of the correct fieldSeparator yet.

If you want to try a different fieldSeparator just set the var accordingly and then call the mutating func parse(maxLines: Int? = nil) on the struct.

Good luck.

Escaping Quotes

For preformance reasons we're using Substrings. That means the parser cannot unescape double double quotes ("") into single double (") quotes. That has to be done while converting the Arrays of Substrings into proper data. Quick and dirty example how to do this, here in the context of a simple SwiftUI View:

ForEach(line.fields, id:\.self) { field in
  Text(field.replacingOccurrences(of: "\"\"", with: "\""))

Note: direct usage of the Substrings in a SwiftUI ForEach like this is not recommended for production because

the ID  occurs multiple times within the collection, this will give undefined results!

Don't do like I do. ;-)

Testing / trying

There is a ContentView.swift file with around 30 test "files" in it to try inside an Xcode iPhone App Project. It's a little hacky but it did get the job done to debug the parser pretty okay.

Known issue

If a field is improperly quoted (it has an opening double quote (") but no such closing quote before end of file) then the last character of this field (which should be the closing double quote) is omitted.

You might also like...
Passing data from a couple of screen into a Model
Passing data from a couple of screen into a Model

Passing-Data Passing data from a couple of screen into a Model Introduction Hi, this video is just a representation project from this Video by Essenti

 Extendy - A set of useful string extensions.
Extendy - A set of useful string extensions.

Extendy A set of useful string extensions. Requirements iOS 11.0+ Swift 5+ Installation CocoaPods Extendy is available through CocoaPods. To install i

This package will contain the standard encodings/decodings/hahsing used by the String Conversion Tool app.

This package will contain the standard encodings/decodings/hahsing used by the String Conversion Tool app. It will also, however, contain extra encoding/decoding methods (new encoding/decoding)

EmbeddedStringsKit: Representation localized string in code

EmbeddedStringsKit Representation localized string in code Usage public struct L

ParserCombinators - String Parser Construction Kit

ParserCombinators provides a set of elementary building blocks for deriving stru

DGLabelSize - Functions that calculate the size of uilabel based on different string lengths
DGLabelSize - Functions that calculate the size of uilabel based on different string lengths

DGLabelSize Functions that calculate the size of uilabel based on different stri

Mac app to change .ipa file app icons and display names

IPAEdit Mac app to change .ipa file app icon, display name, and app version to avoid updates Compatible with macOS 10.11+ Install To install either cl

WordScramble app for demonstrating loading an external txt file and working with it
WordScramble app for demonstrating loading an external txt file and working with it

WordScramble-v2 WordScramble app for demonstrating loading an external txt file and working with it App for creating anagrams from given 8 letter word

A reverse engineering tool to restore stripped symbol table and dump Objective-C class or Swift types for machO file.

A reverse engineering tool to restore stripped symbol table and dump Objective-C class or Swift types for machO file.

Owner
Matthias
Indie
Matthias
Converter for your Rigol Oscilloscope .CSV files to LtSpice

rigol2spice A program to convert Rigol oscilloscope's .CSV files to a format readable by LTspice. Your Rigol oscilloscope can output .CSV files that c

Rui Carneiro 4 Aug 31, 2022
A simple, but efficient CSV Parser, written in Swift.

CSV CSV.swift is a powerful swift library for parsing CSV files that supports reading as [String], [String: String] and Decodable, without sacrificing

Ben Koska 4 Nov 28, 2022
Decode a string encoded in Base64 into an https link and launch it in Google Chrome

Decode a string encoded in Base64 into an https link and launch it in Google Chr

Jerry 0 Jan 2, 2022
📘A library for isolated developing UI components and automatically taking snapshots of them.

A library for isolated developing UI components and automatically taking snapshots of them. Playbook Playbook is a library that provides a sandbox for

Playbook 969 Dec 27, 2022
Array diffs as collection view wants it - now in Swift ✨

Doppelganger-Swift Inspired by Doppelganger written in Swift Features Removes confusion from users when data changes Animates moving, inserting and de

Szymon Maślanka 9 Jul 9, 2019
Merges a given number of PDF files into one file using the PDFKit framework

Titanium iOS PDF Merge Merges a given number of PDF files into one file using the PDFKit framework Requirements iOS 11+ Titanium SDK 9+ API's Methods

Hans Knöchel 6 Jan 26, 2022
Read iOS 15 privacy insight '.ndjson' file into your human brain.

Insight Read iOS 15 privacy insight '.ndjson' file into your human brain. Written in SwiftUI. Feature Compile records into app summary Relink app info

Lakr Aream 151 Nov 11, 2022
Numerals is a package containing additional numeric types for the Swift programming language.

swift-numerals Numerals is a package containing additional numeric types for the Swift programming language. Contents The package currently provides t

Alexandre H. Saad 0 Jul 28, 2022
Swift package containing collection protocols.

swift-collection-protocols A package containing collection protocols, for the Swift programming language. Overview No overview available. Availability

Alexandre H. Saad 0 Jul 28, 2022
⏲ A tiny package to measure code execution time. Only 20 lines of code.

Measure ⏲ A tiny package to measure code execution time. Measure.start("create-user") let user = User() Measure.finish("create-user") Console // ⏲ Mea

Mezhevikin Alexey 3 Oct 1, 2022