所以我是iphone开发的新手,但我正在尝试学习如何获取CSV文件并将其读取并使用Core Data保存(我认为这是最好的方法吗?)以便我可以将其显示在iphone的桌面视图。下面是我正在使用的csv文件类型的示例;
13,1,1,历史,,,,,, 1个
,263,1,史密斯,鲍勃,大一
,317,2,琼斯,约翰,Sophmore
14,2,1,数学,,,,,, 1个
,311,1,金,玛丽,大一
,352,2,Doe,Fred,Senior
如果第一个数字是类的类型(即13 =历史),第二个数字是多少个部分(即1 = 1个等级),第三个数字是会议模式(即1 =星期一,星期三,星期五) ,然后是班级的名称。我不太关心课程的其余部分,所以我想我可以让它忽略那些角色。
对于第2行和第3行,逗号后面的第一个数字是学号,然后是座位号,然后是姓氏,名字,学年。
所以我认为有两个主要挑战。首先是如何解析数据,以便我可以知道每个类中的许多人和谁,所以我可以将其调用到表视图中(稍后添加),然后我不知道如何将整数值与会议模式或班级名称(即13 =历史,1 =周一/周三/周五)
非常感谢你的帮助
答案 0 :(得分:14)
答案 1 :(得分:5)
此处可以使用NSString
方法componentsSeparatedByString:
,但特定于CSV的库可能更容易使用。这里有一篇关于解析CSV数据的好文章(含代码):
答案 2 :(得分:4)
对于解析,我会使用componentsSeparatedByString:NSString类的方法。这类似于perl或ruby中的split函数
答案 3 :(得分:3)
我有一个用于Objective-C的CSV解析器,它会解析你抛出的任何CSV文件(如果它失败了,请告诉我,以便我可以解决它。)
答案 4 :(得分:0)
您可以使用RegexKitLite。关于如何执行此操作的documentation has an example只有17行,并且包含注释。虽然您的milage可能会有所不同,但我一般认为它是解析CSV数据的最快方法之一,也是最容易修改以满足您需求的方法之一,因为它只需要几行来完成整个事情。< / p>
答案 5 :(得分:0)
你可能想看看Matt Gallagher关于解析CSV的“Cocoa With Love”一文:http://cocoawithlove.com/2009/11/writing-parser-using-nsscanner-csv.html。他写了一个完整的语法和几个有用的课程,你可以直接进入你的项目 霍华德
答案 6 :(得分:0)
@JohnnySoftware指出的文章不再有效,我在wayback machine中找到它,并且正在复制下面的内容:
在很多情况下,MacResearch的读者已经发布了一些问题,询问您如何解析Cocoa中的CSV(逗号分隔值)数据。 CSV是一种用于表示表格的简单标准;它用于各种各样的领域,从科学到金融 - 基本上任何表都需要存储在文本文件中。
我最近在我的闪存卡应用程序Mental Case中添加了CSV导入。在我开始之前,我认为在Google上搜索一些Objective-C示例代码或开源库是一件小事。我在Python等脚本语言中找到了解决方案,但没有基于Cocoa的解决方案。经过一两个小时的搜索,我意识到如果我想要一个可可原生的解决方案,我将不得不自己动手。在这个简短的教程中,我将向您展示我的想法,希望能为您省去自己做的麻烦。 简单的CSV
如果您事先知道数据的结构,并且您不必处理引用的字符串,那么解析CSV实际上可以非常简单。事实上,我在早期的教程中解决了这个问题,该教程以CSV格式存储光谱。
- (BOOL)readFromURL:(NSURL *)absoluteURL ofType:(NSString *)typeName
error:(NSError **)outError
{
NSString *fileString = [NSString stringWithContentsOfURL:absoluteURL
encoding:NSUTF8StringEncoding error:outError];
if ( nil == fileString ) return NO;
NSScanner *scanner = [NSScanner scannerWithString:fileString];
[scanner setCharactersToBeSkipped:
[NSCharacterSet characterSetWithCharactersInString:@"\n, "]];
NSMutableArray *newPoints = [NSMutableArray array];
float energy, intensity;
while ( [scanner scanFloat:&energy] && [scanner scanFloat:&intensity] ) {
[newPoints addObject:
[NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat:energy], @"energy",
[NSNumber numberWithFloat:intensity], @"intensity",
nil]];
}
[self setPoints:newPoints];
return YES;
}
NSScanner类是你用来在Cocoa中进行大部分字符串解析的方法。在上面的示例中,假设CSV文件是特定形式,即它有两列,每列包含一个十进制数。通过告诉扫描仪跳过逗号
[scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@"\n, "]];
每行的解析减少到一行
while ( [scanner scanFloat:&energy] && [scanner scanFloat:&intensity] ) {
scanFloat:方法将尝试读取浮点数,失败时返回NO。因此while循环将继续,直到格式不符合预期。
常规CSV
正如您所看到的,解析CSV数据非常简单,但情况并非总是如此。当你必须处理一般的CSV数据时,事情会变得非常复杂,因为你必须考虑字符串包含引号的可能性,甚至可以扩展到多行。例如,以下是有效的CSV数据行,包含两列:
&#34;快速的棕色狐狸&#34;,&#34;跳过&#34;&#34;懒惰&#34;&#34;,狗&#34;
如果你没有弄明白,双引号在字符串中被视为单引号,给出了两个字符串&#39;快速的棕色狐狸&#39;并且&#39;跳过&#34;懒惰&#34;狗&#39;。
解析这种通用形式的CSV比简单形式困难得多,我花了很长时间才想出一些干净的代码来完成它。但我认为我最终成功了。这是:(更新:我已更改此代码以正确处理所有换行品种。)
@implementation NSString (ParsingExtensions)
-(NSArray *)csvRows {
NSMutableArray *rows = [NSMutableArray array];
// Get newline character set
NSMutableCharacterSet *newlineCharacterSet = (id)[NSMutableCharacterSet whitespaceAndNewlineCharacterSet];
[newlineCharacterSet formIntersectionWithCharacterSet:[[NSCharacterSet whitespaceCharacterSet] invertedSet]];
// Characters that are important to the parser
NSMutableCharacterSet *importantCharactersSet = (id)[NSMutableCharacterSet characterSetWithCharactersInString:@",\""];
[importantCharactersSet formUnionWithCharacterSet:newlineCharacterSet];
// Create scanner, and scan string
NSScanner *scanner = [NSScanner scannerWithString:self];
[scanner setCharactersToBeSkipped:nil];
while ( ![scanner isAtEnd] ) {
BOOL insideQuotes = NO;
BOOL finishedRow = NO;
NSMutableArray *columns = [NSMutableArray arrayWithCapacity:10];
NSMutableString *currentColumn = [NSMutableString string];
while ( !finishedRow ) {
NSString *tempString;
if ( [scanner scanUpToCharactersFromSet:importantCharactersSet intoString:&tempString] ) {
[currentColumn appendString:tempString];
}
if ( [scanner isAtEnd] ) {
if ( ![currentColumn isEqualToString:@""] ) [columns addObject:currentColumn];
finishedRow = YES;
}
else if ( [scanner scanCharactersFromSet:newlineCharacterSet intoString:&tempString] ) {
if ( insideQuotes ) {
// Add line break to column text
[currentColumn appendString:tempString];
}
else {
// End of row
if ( ![currentColumn isEqualToString:@""] ) [columns addObject:currentColumn];
finishedRow = YES;
}
}
else if ( [scanner scanString:@"\"" intoString:NULL] ) {
if ( insideQuotes && [scanner scanString:@"\"" intoString:NULL] ) {
// Replace double quotes with a single quote in the column string.
[currentColumn appendString:@"\""];
}
else {
// Start or end of a quoted string.
insideQuotes = !insideQuotes;
}
}
else if ( [scanner scanString:@"," intoString:NULL] ) {
if ( insideQuotes ) {
[currentColumn appendString:@","];
}
else {
// This is a column separating comma
[columns addObject:currentColumn];
currentColumn = [NSMutableString string];
[scanner scanCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] intoString:NULL];
}
}
}
if ( [columns count] > 0 ) [rows addObject:columns];
}
return rows;
}
@end
(我将此代码发布到公共领域,因此请随意使用。) 此代码旨在成为NSString的一个类别。我们的想法是,它会将字符串解析为行和列,假设它是CSV格式。结果是一个数组数组;包含数组中的条目表示行,而包含的数组中的条目表示每行中的列。
代码本身相当简单:它由一个大的while循环组成,它一直持续到整个字符串被解析为止。内部while循环查看每行CSV数据,查找重要的地标,如行尾,开头或右数引号或逗号。通过跟踪开始和结束引号,它能够正确处理嵌入在引用字符串中的逗号和换行符。
<强>结论强>
NSScanner是一个用于解析字符串的有用类。它可能不像Perl和Python等脚本语言中的正则表达式那么强大,但只有几个方法 - 例如,scanString:intoString:scanUpToCharactersFromSet:intoString:,scanFloat: - 你可以实现很多。如果你需要在你的一个Cocoa项目中进行任何基本的字符串解析,请看一下。