2

运行嵌套的 NSScanner 是解析一串重复元素的最有效方法,还是可以一次完成扫描?

我有一个从命令行调用 ( NSTAsk) 返回到 Apple Compressor 的字符串(没有换行符,换行符纯粹是为了便于这个问题在不滚动的情况下清晰易读):

<jobStatus name="compressor.motn" submissionTime="12/4/10 3:56:16 PM"
 sentBy="localuser" jobType="Compressor" priority="HighPriority" 
 timeElapsed="32 second(s)" timeRemaining="0" timeElapsedSeconds="32"
 timeRemainingSeconds="0" percentComplete="100" resumePercentComplete="100"
 status="Successful" jobid="CD4046D8-CDC1-4F2D-B9A8-460DF6AF184E" 
 batchid="0C9041F5-A499-4D00-A26A-D7508EAF3F85" /jobStatus>

这些在同一个字符串中重复,因此在返回字符串中可能有零到 n 个:

<jobstatus .... /jobstatus><jobstatus .... /jobstatus>
<jobstatus .... /jobstatus>

此外,还可能包含其他对我的代码没有意义的标签(本例中的批处理状态):

<jobstatus .... /jobstatus><batchstatus .... /batchstatus>
<jobstatus .... /jobstatus>

这不是返回的 XML 文档,只是一系列状态块,它们恰好被包装在类似 XML 的标记中。没有任何块是嵌套的。它们本质上都是顺序的。我无法控制返回的数据。

我的目标(以及当前工作的代码)将字符串解析为“作业”,其中包含作业状态块中详细信息的字典。任何其他块(例如批处理状态)和任何其他字符串都将被忽略。我只关心 jobstatus 块的内容。

NSScanner * jobScanner = [NSScanner scannerWithString:dataAsString];
NSScanner * detailScanner = nil;

NSMutableDictionary * jobDictionary = [NSMutableDictionary dictionary];
NSMutableArray * jobsArray = [NSMutableArray array];

NSString * key = @"";
NSString * value = @"";

NSString * jobStatus = @"";

NSCharacterSet * whitespace = [NSCharacterSet whitespaceCharacterSet];

while ([jobScanner isAtEnd] == NO) {

    if ([jobScanner scanUpToString:@"<jobstatus " intoString:NULL] &&
        [jobScanner scanUpToCharactersFromSet:whitespace intoString:NULL] &&
        [jobScanner scanUpToString:@" /jobstatus>" intoString:&jobStatus]) {

        detailScanner = [NSScanner scannerWithString:jobStatus];

        [jobDictionary removeAllObjects];

        while ([detailScanner isAtEnd] == NO) {

            if ([detailScanner scanUpToString:@"=" intoString:&key] &&
                [detailScanner scanString:@"=\"" intoString:NULL] &&
                [detailScanner scanUpToString:@"\"" intoString:&value] &&
                [detailScanner scanString:@"\"" intoString:NULL]) {

                [jobDictionary setObject:value forKey:key];

                //NSLog(@"Key:(%@) Value:(%@)", key, value);
            }
        }

        [jobsArray addObject:
         [NSDictionary dictionaryWithDictionary:jobDictionary]];
    }

}

NSLog(@"Jobs Dictionary:%@", jobsArray);

上面的代码产生以下日志输出:

Jobs Dictionary:(
    {
    batchid = "0C9041F5-A499-4D00-A26A-D7508EAF3F85";
    jobType = Compressor;
    jobid = "CD4046D8-CDC1-4F2D-B9A8-460DF6AF184E";
    name = "compressor.motn";
    percentComplete = 100;
    priority = HighPriority;
    resumePercentComplete = 100;
    sentBy = localuser;
    status = Successful;
    submissionTime = "12/4/10 3:56:16 PM";
    timeElapsed = "32 second(s)";
    timeElapsedSeconds = 32;
    timeRemaining = 0;
    timeRemainingSeconds = 0;
}

这就是问题所在。在我的代码中,我正在扫描字符串,然后当我得到一个数据块时,扫描该数据块以创建一个填充数组的字典。这实际上意味着字符串会被遍历两次。由于这是每 15 到 30 秒左右发生的事情,并且可能包含数百个作业,我认为这是一个潜在的 CPU 和内存占用,并且作为运行它的应用程序可能与 Compressor 应用程序在同一台机器上(即已经是内存和 CPU 猪了)——如果我不需要的话,我不想增加任何负担。

有没有更好的方法让我在遍历它来获取数据时使用 NSScanner?

非常感谢任何建议或建议!

4

1 回答 1

1

您的嵌套没问题,因为您正在使用 jobScanner 扫描的 jobStatus 构建 detailScanner。这不是问题。不过,你还有另外两个。一个是您过多地使用空白字符,但更糟糕的是,由于初始 if 条件的形成方式,您的最外层循环永远不会退出。

改变

if ([jobScanner scanUpToString:@"<jobstatus " intoString:NULL] &&
[jobScanner scanUpToCharactersFromSet:whitespace intoString:NULL] &&
[jobScanner scanUpToString:@" /jobstatus>" intoString:&jobStatus])

if ([jobScanner scanString:@"<jobstatus" intoString:NULL] && 
[jobScanner scanUpToString:@"/jobstatus>" intoString:&jobStatus] && 
[jobScanner scanString:@"/jobstatus>" intoString:NULL])

当然,您可以删除缓存空白字符集的行。您不需要扫描空白字符,也不需要将它们包含在您扫描或扫描到的字符串中。默认情况下,扫描仪会跳过空白字符。取消注释您的第一个 NSLog 语句证明了这一点;输出中的任何地方都没有任何杂散空间。

但是,一旦您扫描到一个给定的字符串,您确实需要扫描该字符串本身,否则您将不会朝着下一次迭代的末尾前进。

除此之外,我认为你的方法是合理的。

于 2010-12-05T03:48:57.023 回答