【问题标题】:Using NSScanner to separate string into NSArray by comma使用 NSScanner 以逗号分隔字符串到 NSArray
【发布时间】:2014-04-18 00:50:10
【问题描述】:

有谁知道我如何使用 NSScanner 将逗号分隔成一个数组,除非逗号嵌入引号中?

在我使用之前:

  NSArray *arrData = [strData componentsSeparatedByString:@","];

但是我在字符串中有引号,里面有逗号,我希望它们不要分开。我以前从未与 NSScanner 合作过,我正在努力接受文档。有没有人做过类似的事情?

【问题讨论】:

  • 为什么不尝试将 componentsSeparatedByString 值从 @"," 修改为 @"\",\"" 。
  • 您需要使用 NSScanner 或者对于这种情况,您认为它不能以正常方式完成。?
  • 我相信唯一的方法是 NSScanner 或 NSRegularExpressions 但是我以前从未使用过这两种方法,所以我有点不知所措。
  • 我尊重你的信念。尝试按照我的建议转义双引号。告诉我。
  • 听起来你有一个 CSV 文件。如果是这样,您可能需要考虑一个合适的CSV parser

标签: objective-c csv nsstring nsarray nsscanner


【解决方案1】:

如果你绝对必须使用 NSScanner,你可以这样做。

        NSScanner *scanner = [[NSScanner alloc] initWithString:@"\"Foo, Inc\",0.00,1.00,\"+1.5%\",\"+0.2%\",\"Foo"];
        NSCharacterSet *characters = [NSCharacterSet characterSetWithCharactersInString:@"\","];
        [scanner setCharactersToBeSkipped:nil];
        NSMutableArray *words = [[NSMutableArray alloc]init];
        NSMutableString *word = [[NSMutableString alloc] init];
        BOOL inQuotes = NO;
        while(scanner.isAtEnd == NO)
        {
            NSString *subString;
            [scanner scanUpToCharactersFromSet:characters intoString:&subString];
            NSUInteger currentLocation = [scanner scanLocation];
            if(currentLocation >= scanner.string.length)
            {
                if(subString.length > 0)
                    [words addObject:subString];
                break;
            }
            if([scanner.string characterAtIndex:currentLocation] == '"')
            {
                inQuotes = !inQuotes;
                if(subString == nil)
                {
                    [scanner setScanLocation:currentLocation + 1];
                    continue;
                }
                [word appendFormat:@"%@",subString];
                if(word.length > 0)
                   [words addObject:word.copy];
                [word deleteCharactersInRange:NSMakeRange(0, word.length)];
            }
            if([scanner.string characterAtIndex:currentLocation] == ',')
            {
                if(subString == nil)
                {
                    [scanner setScanLocation:currentLocation + 1];
                    continue;
                }
                if(inQuotes == NO)
                    [words addObject:subString];
                else
                    [word appendFormat:@"%@,",subString];
            }
            [scanner setScanLocation:currentLocation + 1];
        }

编辑: 这给出了以下输出:

Foo, Inc

0.00

1.00

+1.5%

+0.2%

希望这是你想要的

正如您所见,它变得复杂且非常容易出错,我建议为此使用正则表达式。

【讨论】:

  • 当我插入自己的字符串时,它一直在崩溃。也许正则表达式会更好。我将如何使用正则表达式将其拆分为数组?
  • 还是没有运气。如果有帮助,这是我的字符串的副本:"Foo, Inc",0.00,1.00,"+1.5%","+0.2%","Foo"
  • 如果不调试,我显然无法编写正确的代码。我更新的代码应该可以工作
  • 这是我遍历每个索引后数组的样子:Item 0: Foo Item 1: Inc" Item 2: 0.00 Item 3: 1.00 Item 4: "+1.5%", "+0.2%","Foo 有没有办法用正则表达式做到这一点?
  • 我认为您在输出中错过了 1.00 和 Foo 。现在检查我的代码。它应该工作!哇
【解决方案2】:

这与lead_the_zeppelin's answer 的一般程序相同,但我认为它要简单得多。我们使用NSMutableStringaccum 来构建每个内部评论片段,其中可能包含任意数量的引用片段。

每次迭代,我们都会扫描到逗号、引号或字符串的结尾,以先到者为准。如果我们找到一个逗号,那么到目前为止积累的任何东西都应该被保存。对于引用,我们将所有内容提取到右引号 - 这是避免将引号内的逗号解释为分割点的关键。请注意,如果引号并不总是平衡的,这将不起作用。如果两者都不是,我们已经到了字符串的末尾,所以我们保存累积的字符串并退出。

// Demo data
NSArray * commaStrings = @[@"This, here, \"has\" no quoted, commas.",
                           @"This \"has, no\" unquoted \"commas,\"",
                           @"This, has,no,quotes",
                           @"This has no commas",
                           @"This has, \"a quoted\" \"phrase, followed\", by a, quoted phrase",
                           @"\"This\", one, \"went,\", to, \"mar,ket\"",
                           @"This has neither commas nor quotes",
                           @"This ends with a comma,"];

NSCharacterSet * commaQuoteSet = [NSCharacterSet characterSetWithCharactersInString:@",\""];

for( NSString * commaString in commaStrings ){

    NSScanner * scanner = [NSScanner scannerWithString:commaString];
    // Scanner ignores whitespace by default; turn that off.
    [scanner setCharactersToBeSkipped:nil];

    NSMutableArray * splitStrings = [NSMutableArray new];

    NSMutableString * accum = [NSMutableString new];

    while( YES ){

        // Set to an empty string for the case where the scanner is
        // at the end of the string and won't scan anything;
        // appendString: will die if its argument is nil.
        NSString * currScan = @"";
        // Scan up to a comma or a quote; this will go all the way to
        // the end of the string if neither of those exists.
        [scanner scanUpToCharactersFromSet:commaQuoteSet
                                intoString:&currScan];
        // Add the just-scanned material to whatever we've already got.
        [accum appendString:currScan];

        if( [scanner scanString:@"," intoString:NULL] ){
            // If it's a comma, save the accumulated string,
            [splitStrings addObject:accum];
            // clear it out,
            accum = [NSMutableString new];
            // and keep scanning.
            continue;
        }
        else if( [scanner scanString:@"\"" intoString:NULL] ) {
            // If a quote, append the quoted segment to the accumulation,
            [scanner scanUpToString:@"\""
                         intoString:&currScan];
            [accum appendFormat:@"\"%@\"", currScan];
            // and continue, appending until the next comma.
            [scanner scanString:@"\"" intoString:NULL];
            continue;
        }
        else {
            //Otherwise, there's nothing else to split; 
            // just save the remainder of the string
            [splitStrings addObject:accum];
            break;
        }

    }
    NSLog(@"%@", splitStrings);
}

另外,as Chuck suggested,您可能只想获得一个 CSV 解析器。

【讨论】:

    猜你喜欢
    • 2012-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-25
    • 1970-01-01
    相关资源
    最近更新 更多