Вложенная эффективность NSScanner - PullRequest
2 голосов
/ 05 декабря 2010

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

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

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

1 Ответ

1 голос
/ 05 декабря 2010

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

Изменение

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 подтверждает это; в выходных данных нет пустых мест.

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

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

...