运行嵌套的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>
这些在同一个字符串中重复,因此在返回字符串中可能有0到n:
<jobstatus .... /jobstatus><jobstatus .... /jobstatus>
<jobstatus .... /jobstatus>
此外,可能还有其他标签对我的代码没有意义(本例中为batchstatus):
<jobstatus .... /jobstatus><batchstatus .... /batchstatus>
<jobstatus .... /jobstatus>
这不是返回的XML文档,只是一系列状态块,恰好包含在XML标记中。没有嵌套的块。它们本质上都是连续的。我无法控制返回的数据。
我的目标(以及当前正在运行的代码)将字符串解析为包含jobstatus块中详细信息字典的“作业”。任何其他块(例如batchstatus)和任何其他字符串都将被忽略。我只关心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获取数据时,是否有更好的方法可以使用NSScanner?
非常感谢任何建议或推荐!
答案 0 :(得分: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声明就是这样;输出中没有任何杂散空间。
但是,一旦你扫描到一个给定的字符串,你确实需要扫描该字符串本身,或者你不会在下一次迭代中向前移动。
除此之外,我认为你的方法很合理。