解析 CSV:NSScanner 如何识别空字段(即 ,,)?

发布于 2024-11-02 18:07:34 字数 2823 浏览 0 评论 0原文

我对 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:&note];
    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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

记忆で 2024-11-09 18:07:34

在 Objective-C 中解析 CSV?这听起来很熟悉:

https://github.com/davedelong/CHCSVParser

免责声明:我写的。 :)


对于您正在做的事情,您可以只获取文件并通过类似 +[NSArray arrayWithContentsOfCSVFile:encoding:error:] 方法运行,或者您可以将其读入字符串并做这样的事情:

NSString *csv = @"\"Personal\",\"2011-01-01\",\"Personal\",\"Cigarettes\",,4.60,\"Cash\",\"\",";
NSLog(@"%@", [csv CSVComponents]);

哪个日志:(

2011-04-22 09:51:16.651 CHCSVParser[2658:903] (
        (
        Personal,
        "2011-01-01",
        Personal,
        Cigarettes,
        "",
        "4.60",
        Cash,
        ""
    )
)

请注意,这是 NSArraysNSStringsNSArray

如果您担心内存累积,那么您还可以直接使用 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:

NSString *csv = @"\"Personal\",\"2011-01-01\",\"Personal\",\"Cigarettes\",,4.60,\"Cash\",\"\",";
NSLog(@"%@", [csv CSVComponents]);

Which logs:

2011-04-22 09:51:16.651 CHCSVParser[2658:903] (
        (
        Personal,
        "2011-01-01",
        Personal,
        Cigarettes,
        "",
        "4.60",
        Cash,
        ""
    )
)

(Note that this is an NSArray of NSArrays of NSStrings)

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 how NSXMLParser works.

流绪微梦 2024-11-09 18:07:34

扫描仪看不到您的空白字段的原因是您告诉它跳过逗号。您使用一组 3 个字符调用了 setCharactersToBeSkipped:

  1. '\n' 换行符
  2. ',' 逗号
  3. ' ' 空格

然后您要求扫描器“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:

  1. '\n' The newline character
  2. ',' Comma
  3. ' ' Space

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.

又怨 2024-11-09 18:07:34

请查看这篇关于 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文