Эффективность вложенного NSScanner

Является ли запуск вложенного 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>

Кроме того, могут быть включены другие теги, которые не имеют значения для моего кода (batchstatus в этом примере):

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

Это НЕ XML-документ, который возвращается, а просто серия блоков статуса, которые оказались завернуты в XML-подобный тег. Ни один из блоков не является вложенным. Все они носят последовательный характер. Я не контролирую возвращаемые данные.

Моя цель (и в настоящее время работающий код) разбирает строку на «задания», которые содержат словари деталей в блоке jobstatus. Любые другие блоки (например, пакетный статус) и любые другие строки игнорируются. Меня интересует только содержимое блоков 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 секунд или около того и может содержать сотни заданий, я вижу в этом потенциальную нагрузку на ЦП и память, а приложение, выполняющее это, может находиться на том же компьютере, что и приложение Compressor (которое уже потребляет память и процессор) - я не хочу добавлять какую-либо нагрузку, если мне это не нужно.

Есть ли лучший способ использовать NSScanner для получения данных?

Любые советы или рекомендации очень ценятся!


person Hooligancat    schedule 05.12.2010    source источник


Ответы (1)


С вашей вложенностью все в порядке, поскольку вы создаете detailScanner с помощью jobStatus, который сканировал jobScanner. Это не проблема. Но у тебя есть еще двое. Один из них заключается в том, что вы слишком много потеете по пробельным символам, но, что еще хуже, ваш самый внешний цикл никогда не выйдет из-за того, как формируется ваше начальное условие if.

Изменять

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

to

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

Конечно, вы можете удалить свою строку, в которой вы кешируете свой набор символов пробела. Вам не нужно сканировать пробельные символы, и вам не нужно включать их в строки, которые вы сканируете или сканируете. По умолчанию сканеры пропускают пробельные символы. Раскомментирование вашего первого оператора NSLog подтверждает это; в выводе нет никаких случайных пробелов.

Но вам нужно, как только вы отсканировали до заданной строки, отсканировать эту строку, иначе вы не собираетесь двигаться вперед к концу для следующей итерации.

Кроме этого, я думаю, что ваш подход является правильным.

person Extra Savoir-Faire    schedule 05.12.2010
comment
трудолюбивый - спасибо! Эти изменения внесены и работают без сбоев. Я был ботом, обеспокоенным набором символов, потому что согласно документации это дорогостоящая операция, но, конечно же, я пропустил бит о пропуске пробела, так что это все равно стало спорным! Еще раз спасибо! - person Hooligancat; 05.12.2010