Импортировать данные .csv в массив

Я использую Objective-C последние годы. Теперь я пробую Xcode 6 beta 4 с быстрым.

Я хочу импортировать CSV-форму моего веб-сервера в массив. Мой старый код в Objective-C был:

NSString *stringURL = @"https:// [URL] /versionen/versionen.csv";
NSURL  *url = [NSURL URLWithString:stringURL];
NSData *urlData = [NSData dataWithContentsOfURL:url];
if ( urlData )
{
    NSString *csvResponseString = [[NSString alloc] initWithData:urlData   encoding:NSUTF8StringEncoding];
    NSArray         *MZVersionDatenZeilen = [csvResponseString componentsSeparatedByString:@"\n"];
    NSEnumerator    *MZVersionEnumerator = [MZVersionDatenZeilen objectEnumerator];
    NSMutableArray  *MZVersionDatenArray = [NSMutableArray arrayWithCapacity:[MZVersionDatenZeilen count]];
    NSString        *MZVersionZeile;
    while (MZVersionZeile = [MZVersionEnumerator nextObject])
    {
        [MZVersionDatenArray addObject:[MZVersionZeile componentsSeparatedByString:@";"]];
    }
}

Как я могу сделать это в Swift? Есть ли лучшие рекомендации - рекомендации?

Ответ 1

Доступно несколько быстрых библиотек:

CSVImporter, который является асинхронным парсером, подходящим для работы с большими файлами csv.

let path = "path/to/your/CSV/file"
let importer = CSVImporter<[String]>(path: path)
importer.startImportingRecords { $0 }.onFinish { importedRecords in
    for record in importedRecords {
        // record is of type [String] and contains all data in a line
    }
}

SwiftCSV, который представляет собой простую библиотеку синтаксического анализа CSV для OSX и iOS.

let csvURL = NSURL(string: "users.csv")!
var error: NSErrorPointer = nil
let csv = CSV(contentsOfURL: csvURL, error: error)

// Rows
let rows = csv.rows
let headers = csv.headers  //=> ["id", "name", "age"]
let alice = csv.rows[0]    //=> ["id": "1", "name": "Alice", "age": "18"]
let bob = csv.rows[1]      //=> ["id": "2", "name": "Bob", "age": "19"]

// Columns
let columns = csv.columns
let names = csv.columns["name"]  //=> ["Alice", "Bob", "Charlie"]
let ages = csv.columns["age"]    //=> ["18", "19", "20"]

и CSwiftV, который является парсером csv, соответствующим rfc4180, но, по словам автора, он все в памяти, поэтому не подходит для больших файлов.

let inputString = "Year,Make,Model,Description,Price\r\n1997,Ford,E350,descrition,3000.00\r\n1999,Chevy,Venture,another description,4900.00\r\n"
let csv = CSwiftV(String: inputString)

let headers = csv.headers // ["Year","Make","Model","Description","Price"]
let rows = csv.rows 
// [
//  ["1997","Ford","E350","descrition","3000.00"],
//  ["1999","Chevy","Venture","another description","4900.00"]
// ]

Ответ 2

Не используйте SwiftCSV в соответствии с самым последним ответом.

SwiftCSV не обрабатывает двойные кавычки прямо сейчас, поэтому, если любые данные в вашем файле CSV имеют разрывы строк или запятые в нем, SwiftCSV не будет работать. И вы можете потратить драгоценное время на разработку, узнав, почему он не работает... чтобы сохранить вас в то время, просто используйте другую библиотеку.

Библиотека CSwiftV отлично работала для меня: https://github.com/Daniel1of1/CSwiftV

Он обрабатывает цитируемый текст, символы новой строки, запятые, работает как очарование моих данных. Он также имеет модульные тесты и соответствует стандарту rfc4180.

Ответ 3

Каждый ответ требует, чтобы вы установили/загрузили стороннюю утилиту, но это может быть не оптимальным, если файл, с которым вы работаете, чрезвычайно прост или вы работаете в компании, которая ограничивает сторонний код.

Итак, я решил, что просто опубликую невероятно простой, обычный CSV-код обработки файлов, который люди могут использовать в качестве базы и изменить при необходимости для простой обработки CSV.

do {
    let file = try String(contentsOf: fileUrl)
    let rows = file.components(separatedBy: .newlines)
    for row in rows {
        let fields = row.replacingOccurrences(of: "\"", with: "").components(separatedBy: ",")
        print(fields)
    }
} catch {
    print(error)
}

Это будет обрабатывать любые CSV файлы, которые, как вы знаете, не будут содержать кавычки и запятые, как часть содержимого поля, которые в моем случае являются большинством файлов CSV. Что-то более сложное, чем это, я рекомендую использовать одну из библиотек, размещенную в других ответах.

Я просто надеюсь, что это поможет кому-то немного набирать текст.

Ответ 4

I рекомендую использовать CSVImporter - он заботится о вещах вроде цитируемого текста (после RFC 4180) для вас и даже без проблем обрабатывает очень большие файлы.

По сравнению с другими решениями он работает как асинхронно (предотвращает задержки), а читает файл CSV по строке вместо того, чтобы загружать всю строку в память (предотвращает проблемы с памятью), Кроме того, он прост в использовании и обеспечивает красивые обратные вызовы для указания сбоя, прогресса, завершения и даже сопоставления данных, если вы этого хотите.


Самый простой способ использования - это (дает вам каждую строку как массив строк):

let path = "path/to/your/CSV/file"
let importer = CSVImporter<[String]>(path: path)
importer.startImportingRecords { $0 }.onFinish { importedRecords in
    for record in importedRecords {
        // record is of type [String] and contains all data in a line
    }
}

Воспользуйтесь более сложными функциями, такими как сопоставление данных и обратные вызовы:

let path = "path/to/Hogwarts/students"
let importer = CSVImporter<Student>(path: path)
importer.startImportingRecords { recordValues -> Student in

    // define your data mapping here
    return Student(firstName: recordValues[0], lastName: recordValues[1])

}.onProgress { importedDataLinesCount in

    // use this to indicate progress
    print("\(importedDataLinesCount) lines were already imported.")

}.onFinish { importedRecords in
    for student in importedRecords {
        // now importedRecords is an array of Student objects
    }
}