解析 CSV:NSScanner 如何识别空字段(即 ,,)?
我对 Xcode 非常陌生,并尝试(数百万人)解析 CSV 文件。我已经阅读了很多贡献并且正在管理它,但是当我的 NSScanner 拦截一个空字段时遇到问题:“Field_A,Field_B,Field_D”。我猜这是因为它默认忽略空白,或者在这种情况下根本没有空间。
字符串是:
“个人”,“2011-01-01”,“个人”,“香烟”,,4.60,“现金”,“”,
我尝试使用 scanLocation 对其进行调试:
2011-04-22 15:57:32.414 Spending[42015:a0f] Before while...scan location is:0
2011-04-22 15:57:32.414 Spending[42015:a0f] Account: "Personal" - scan location is:10
2011-04-22 15:57:32.415 Spending[42015:a0f] Date: "2011-01-01" - scan location is:23
2011-04-22 15:57:32.415 Spending[42015:a0f] Category: "Personal" - scan location is:34
2011-04-22 15:57:32.416 Spending[42015:a0f] Subcategory: "Cigarettes" - scan location is:47
2011-04-22 15:57:32.416 Spending[42015:a0f] Income: 4.600000 - scan location is:53
2011-04-22 15:57:32.416 Spending[42015:a0f] Expense: 0.000000 - scan location is:53
2011-04-22 15:57:32.417 Spending[42015:a0f] Payment: "Cash" - scan location is:60
2011-04-22 15:57:32.417 Spending[42015:a0f] Note: "" - scan location is:63
正如您所看到的,即使费用字段没有值(应该是 4.60)。
这是相关的代码:
NSScanner *scanner = [NSScanner scannerWithString:fileString];
[scanner setCharactersToBeSkipped: [NSCharacterSet characterSetWithCharactersInString:@"\n, "]];
NSString *account, *date, *category, *subcategory, *payment, *note;
float income, expense;
// Set up data delimiter using comma
NSCharacterSet *commaSet;
commaSet = [NSCharacterSet characterSetWithCharactersInString:@","];
NSLog (@"Before while...scan location is:%d\n", scanner.scanLocation);
[scanner scanUpToCharactersFromSet:commaSet intoString:&account];
NSLog(@"Account: %@ - scan location is:%d\n",account, scanner.scanLocation);
[scanner scanUpToCharactersFromSet:commaSet intoString:&date];
NSLog(@"Date: %@ - scan location is:%d\n",date, scanner.scanLocation);
[scanner scanUpToCharactersFromSet:commaSet intoString:&category];
NSLog(@"Category: %@ - scan location is:%d\n",category, scanner.scanLocation);
[scanner scanUpToCharactersFromSet:commaSet intoString:&subcategory];
NSLog(@"Subcategory: %@ - scan location is:%d\n",subcategory, scanner.scanLocation);
[scanner scanFloat:&income];
NSLog(@"Income: %f - scan location is:%d\n",income, scanner.scanLocation);
[scanner scanFloat:&expense];
NSLog(@"Expense: %f - scan location is:%d\n",expense, scanner.scanLocation);
[scanner scanUpToCharactersFromSet:commaSet intoString:&payment];
NSLog(@"Payment: %@ - scan location is:%d\n",payment, scanner.scanLocation);
[scanner scanUpToCharactersFromSet:commaSet intoString:¬e];
NSLog(@"Note: %@\n - scan location is:%d",note, scanner.scanLocation);
我尝试仔细查看 NSScanner 类参考,但无法得到一个想法?你有吗?
谢谢,法布里齐奥。
I am very new to Xcode and trying - as millions - to parse a CSV file. I have read many contributions and I am managing it but I have a problem when my NSScanner intercepts an empty field: "Field_A, Field_B,, Field_D". I guess it is because it ignores empty space by default, or in this case no space at all.
String is:
"Personal","2011-01-01","Personal","Cigarettes",,4.60,"Cash","",
I tried to debug it using scanLocation:
2011-04-22 15:57:32.414 Spending[42015:a0f] Before while...scan location is:0
2011-04-22 15:57:32.414 Spending[42015:a0f] Account: "Personal" - scan location is:10
2011-04-22 15:57:32.415 Spending[42015:a0f] Date: "2011-01-01" - scan location is:23
2011-04-22 15:57:32.415 Spending[42015:a0f] Category: "Personal" - scan location is:34
2011-04-22 15:57:32.416 Spending[42015:a0f] Subcategory: "Cigarettes" - scan location is:47
2011-04-22 15:57:32.416 Spending[42015:a0f] Income: 4.600000 - scan location is:53
2011-04-22 15:57:32.416 Spending[42015:a0f] Expense: 0.000000 - scan location is:53
2011-04-22 15:57:32.417 Spending[42015:a0f] Payment: "Cash" - scan location is:60
2011-04-22 15:57:32.417 Spending[42015:a0f] Note: "" - scan location is:63
And as you can see after that even expense field gets no value (should be 4.60).
Here is the relevant piece of code:
NSScanner *scanner = [NSScanner scannerWithString:fileString];
[scanner setCharactersToBeSkipped: [NSCharacterSet characterSetWithCharactersInString:@"\n, "]];
NSString *account, *date, *category, *subcategory, *payment, *note;
float income, expense;
// Set up data delimiter using comma
NSCharacterSet *commaSet;
commaSet = [NSCharacterSet characterSetWithCharactersInString:@","];
NSLog (@"Before while...scan location is:%d\n", scanner.scanLocation);
[scanner scanUpToCharactersFromSet:commaSet intoString:&account];
NSLog(@"Account: %@ - scan location is:%d\n",account, scanner.scanLocation);
[scanner scanUpToCharactersFromSet:commaSet intoString:&date];
NSLog(@"Date: %@ - scan location is:%d\n",date, scanner.scanLocation);
[scanner scanUpToCharactersFromSet:commaSet intoString:&category];
NSLog(@"Category: %@ - scan location is:%d\n",category, scanner.scanLocation);
[scanner scanUpToCharactersFromSet:commaSet intoString:&subcategory];
NSLog(@"Subcategory: %@ - scan location is:%d\n",subcategory, scanner.scanLocation);
[scanner scanFloat:&income];
NSLog(@"Income: %f - scan location is:%d\n",income, scanner.scanLocation);
[scanner scanFloat:&expense];
NSLog(@"Expense: %f - scan location is:%d\n",expense, scanner.scanLocation);
[scanner scanUpToCharactersFromSet:commaSet intoString:&payment];
NSLog(@"Payment: %@ - scan location is:%d\n",payment, scanner.scanLocation);
[scanner scanUpToCharactersFromSet:commaSet intoString:¬e];
NSLog(@"Note: %@\n - scan location is:%d",note, scanner.scanLocation);
I tried looking carefully through NSScanner Class Reference, but could not get an idea? Do you have any?
Thanks, Fabrizio.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在 Objective-C 中解析 CSV?这听起来很熟悉:
https://github.com/davedelong/CHCSVParser
免责声明:我写的。 :)
对于您正在做的事情,您可以只获取文件并通过类似
+[NSArray arrayWithContentsOfCSVFile:encoding:error:]
方法运行,或者您可以将其读入字符串并做这样的事情:哪个日志:(
请注意,这是
NSArrays
的NSStrings
的NSArray
)如果您担心内存累积,那么您还可以直接使用
CHCSVParser
并通过委托接收信息。它的操作方式与 NSXMLParser 的工作方式几乎相同。Parsing CSV in Objective-C? That sounds familiar:
https://github.com/davedelong/CHCSVParser
Disclaimer: I wrote it. :)
For what you're doing, you could just take the file and run in through something like the
+[NSArray arrayWithContentsOfCSVFile:encoding:error:]
method, or you could read it into a string and do something like this:Which logs:
(Note that this is an
NSArray
ofNSArrays
ofNSStrings
)If you're concerned about memory buildup, then you could also use a
CHCSVParser
directly and receive information via a delegate. It operates pretty much identically to howNSXMLParser
works.扫描仪看不到您的空白字段的原因是您告诉它跳过逗号。您使用一组 3 个字符调用了 setCharactersToBeSkipped:
然后您要求扫描器“scanFloat”,它会遍历任何可跳过的字符,直到达到十进制数。这就是跳过空字段的方式。
如果您想捕获空字段,请从要跳过的字符集中删除逗号。然后,每当扫描函数找到空字段时,它都会返回 NO。发生这种情况时,您可能必须手动增加扫描位置。
The reason why the scanner doesn't see your empty field is because you told it to skip commas. You called setCharactersToBeSkipped with a set of 3 characters:
When you then ask the scanner to "scanFloat", it goes over any skippable character until it reaches a decimal number. This is how the empty field gets skipped.
If you want to catch empty fields, remove the comma from your set of characters to skip. Then, any time a scan function find an empty field, it will return NO. You might have to increment the scanning position manually when this happens.
请查看这篇关于 CSV 扫描仪的文章。
这是另一篇 文章
Dave DeLong 的解决方案也很有效。
底线:CSV 看起来微不足道,但如果您想优雅地处理向您抛出的任何 CSV,则事实并非如此。
Take a look at this article on CSV Scanners.
Here is another article
Dave DeLong's solution also works great.
Bottom line: CSV seems trivial, but it really is not if you are wanting to handle any CSV thrown at you gracefully.