One of the features I’m adding to an upcoming app is the ability to import CSV files. For that purpose I looked around for code already available (and found several options, see below), however none of them compelled me enough so I decided to create my own.
The main objective was to make it as simple as possible and, of course, coded in Swift 2. Note however that I’m still learning so if you would have any suggestions / feedback send them my way! Here it is in all of its glory:
//
// CSVImporter.swift
// Controller
//
// Created by Marc on 5/8/15.
// Copyright (c) 2015 MMV Solucions S.L. All rights reserved.
//
import Cocoa
class CSVImporter: NSObject {
var columnDelimiter = “,”
var textDelimiter = “\””
var rowDelimiter = “\n”
var doesItHaveHeader = true
var rowsFromString : Array<String> = []
var finalParsedCsv : Array<Array<String>> = []
func retrieveCsvFileAndReturnRows(path path: String ) -> Array<Array<String>>? { //Main
let stringToParse: String?
do{
stringToParse = try String(contentsOfFile: path, encoding: NSUTF8StringEncoding)
} catch _ {
stringToParse = nil
}
var unwrappedStringToParse=“”
if (stringToParse == nil) { return nil } else {
unwrappedStringToParse = stringToParse! }
//Cleaning string
unwrappedStringToParse = stringToParse!.stringByReplacingOccurrencesOfString(“\r”, withString: “\n”)
unwrappedStringToParse = unwrappedStringToParse.stringByReplacingOccurrencesOfString(“\n\n”, withString: “\n”)
//Storing by rows
rowsFromString = unwrappedStringToParse.componentsSeparatedByString(rowDelimiter)
//Removing header
if (doesItHaveHeader == true){
rowsFromString.removeAtIndex(0)
}
//Converting and adding rows
for iteratorString in rowsFromString {
if(iteratorString.rangeOfString(textDelimiter) != nil){ //We have detected double quotes
let arrayContainingDoubleQuotes = iteratorString.componentsSeparatedByString(columnDelimiter)
var newArrayAccountingForQuotes : Array <String> = []
var tempArrayContainingNewWord : Array <String> = []
var inDoubleQuoteLoop = false
var newStringFromSplittedWord = “”
for stringToTestForDoublequotes in arrayContainingDoubleQuotes{
if stringToTestForDoublequotes.rangeOfString(textDelimiter) != nil || inDoubleQuoteLoop == true {
if stringToTestForDoublequotes.rangeOfString(textDelimiter) != nil && inDoubleQuoteLoop == false {
tempArrayContainingNewWord.append(stringToTestForDoublequotes)
inDoubleQuoteLoop = true
}else{
tempArrayContainingNewWord.append(stringToTestForDoublequotes)
newStringFromSplittedWord = “”.join(tempArrayContainingNewWord)
newArrayAccountingForQuotes.append(newStringFromSplittedWord)
//Maybe add here option to remove “
inDoubleQuoteLoop = false
}
}else{ //No double quotes found and not in the middle of text, add to new array
newArrayAccountingForQuotes.append(stringToTestForDoublequotes)
}
}
finalParsedCsv.append(newArrayAccountingForQuotes)
}else{
finalParsedCsv.append(iteratorString.componentsSeparatedByString(columnDelimiter))
}
}
//Final cleaning
var row = 0
for iteratorForFinalCleaning in finalParsedCsv{
var column = 0
for _ in iteratorForFinalCleaning{
//Get the text of these coordinates
var tempStringToRemoveCommas = finalParsedCsv[row][column]
if (tempStringToRemoveCommas.rangeOfString(textDelimiter) != nil){
//Do the needed changes into the text
tempStringToRemoveCommas = tempStringToRemoveCommas.stringByReplacingOccurrencesOfString(textDelimiter, withString: “”)
//Add result back to the arrayOfParsedContent
finalParsedCsv[row].insert(tempStringToRemoveCommas, atIndex: column)
}
column++
}
row++
}
returnfinalParsedCsv
}
}
Remember I’m still on my Swift beginnings, if you want other options check out SwiftCSV or this post.