应用程序启动时,我需要将数据预加载到我的 tableView 中。所以我通过解析 .csv 文件来使用核心数据。为此,我正在遵循本教程。 这是我的 parseCSV 函数
func parseCSV (contentsOfURL: NSURL, encoding: NSStringEncoding, error: NSErrorPointer) -> [(stationName:String, stationType:String, stationLineType: String, stationLatitude: String, stationLongitude: String)]? {
// Load the CSV file and parse it
let delimiter = ","
var stations:[(stationName:String, stationType:String, stationLineType: String, stationLatitude: String, stationLongitude: String)]?
let content = String(contentsOfURL: contentsOfURL, encoding: encoding, error: error)
stations = []
let lines:[String] = content.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet()) as [String]
for line in lines {
var values:[String] = []
if line != "" {
// For a line with double quotes
// we use NSScanner to perform the parsing
if line.rangeOfString("\"") != nil {
var textToScan:String = line
var value:NSString?
var textScanner:NSScanner = NSScanner(string: textToScan)
while textScanner.string != "" {
if (textScanner.string as NSString).substringToIndex(1) == "\"" {
textScanner.scanLocation += 1
textScanner.scanUpToString("\"", intoString: &value)
textScanner.scanLocation += 1
} else {
textScanner.scanUpToString(delimiter, intoString: &value)
}
// Store the value into the values array
values.append(value as! String)
// Retrieve the unscanned remainder of the string
if textScanner.scanLocation < textScanner.string.characters.count {
textToScan = (textScanner.string as NSString).substringFromIndex(textScanner.scanLocation + 1)
} else {
textToScan = ""
}
textScanner = NSScanner(string: textToScan)
}
// For a line without double quotes, we can simply separate the string
// by using the delimiter (e.g. comma)
} else {
values = line.componentsSeparatedByString(delimiter)
}
// Put the values into the tuple and add it to the items array
let station = (stationName: values[0], stationType: values[1], stationLineType: values[2], stationLatitude: values[3], stationLongitude: values[4])
stations?.append(station)
}
}
return stations
}
这是我的示例 .csv 文件
Rithala,Underground,Yellow Line,28.7209,77.1070
但是我在这行遇到错误
let station = (stationName: values[0], stationType: values[1], stationLineType: values[2], stationLatitude: values[3], stationLongitude: values[4])
stations?.append(station)
致命错误:数组索引超出范围
我做错了什么?请帮助我。
这是将 CSV 文件解析为 Swift 代码的万无一失的方法(我在这里使用 Swift 5)。 我将为房间里的任何初学者讲解每个步骤。
假设您的 CSV 文件如下所示:
Firstname,Last name,Age,Registered
Duncan,Campbell,40,True
Tobi,Dorner,36,False
Saskia,Boogarts,29,True
1)。我们需要一个结构(或对象)来保存每行数据。 让我们用这个:
struct Person {
var firstName: String
var lastName: String
var age: Int
var isRegistered: Bool
}
2)我们还需要一个变量来保存每个
Person
的数组。
var people = [Person]()
3) 现在 - 将 CSV 文件添加到您的 XCode 项目中(您可以将其拖放到您的项目中)。 确保它有一个合理的名称(例如 data.csv)。
4) 您现在需要“定位”您想要使用的数据。 创建一个 filepath 告诉代码在哪里可以找到你的 csv 文件:
guard let filepath = Bundle.main.path(forResource: "data", ofType: "csv") else {
return
}
5)现在我们要读取这个文件的内容。 首先,我们将整个文件转换为一个长String。
var data = ""
do {
data = try String(contentsOfFile: filepath)
} catch {
print(error)
return
}
6)我们现在有一个字符串,其中一行中包含all数据。 我们希望将其拆分为一个“字符串数组”,数据中的每一行对应一个字符串。 (顺便说一句,\n
表示“新行”)
let rows = data.components(separatedBy: "\n")
7)我们现在有一个包含 4 行的数组 - 一行用于标题,3 行用于数据中的每个人。 我们对第一个标题行不感兴趣,因此我们可以删除该标题行。 (如果您的数据中没有标题行,请忽略此步骤)
rows.removeFirst()
8)现在循环每一行。 目前,每一行都是一个字符串(例如
Duncan,Campbell,40,True
),但我们希望将其拆分为每 4 列的数组。
for row in rows {
let columns = row.components(separatedBy: ",")
9)我们现在有一个数组
columns
,其中有 4 个字符串。 让我们将每一列转换为正确的数据类型。
let firstName = columns[0]
let lastName = columns[1]
let age = Int(columns[2]) ?? 0
let isRegistered = columns[3] == "True"
10) 现在我们可以创建 Person 对象,并将其附加到我们的数组中。
let person = Person(firstName: firstName, lastName: lastName, age: age, isRegistered: isRegistered)
people.append(person)
以下是感兴趣的人的完整代码:
struct Person {
var firstName: String
var lastName: String
var age: Int
var isRegistered: Bool
}
var people = [Person]()
func convertCSVIntoArray() {
//locate the file you want to use
guard let filepath = Bundle.main.path(forResource: "data", ofType: "csv") else {
return
}
//convert that file into one long string
var data = ""
do {
data = try String(contentsOfFile: filepath)
} catch {
print(error)
return
}
//now split that string into an array of "rows" of data. Each row is a string.
var rows = data.components(separatedBy: "\n")
//if you have a header row, remove it here
rows.removeFirst()
//now loop around each row, and split it into each of its columns
for row in rows {
let columns = row.components(separatedBy: ",")
//check that we have enough columns
if columns.count == 4 {
let firstName = columns[0]
let lastName = columns[1]
let age = Int(columns[2]) ?? 0
let isRegistered = columns[3] == "True"
let person = Person(firstName: firstName, lastName: lastName, age: age, isRegistered: isRegistered)
people.append(person)
}
}
}
如果更换
let content = String(contentsOfURL: contentsOfURL, encoding: encoding, error: error)
与:
if let data = NSData(contentsOfURL: contentsOfURL) {
if let content = NSString(data: data, encoding: NSUTF8StringEncoding) {
//existing code
}
}
然后代码将适用于您的示例文件。
values
数组并不像您想象的那样有 5 个元素。我会在出现错误的行上放置一个断点,并检查您的
values
变量并查看其中有多少个。由于你的 .csv 文件显然有 5 个元素长,那么我猜你的解析出了问题。