2

ネストされた NSScanner を実行することは、繰り返し要素の文字列を解析するための最も効率的な方法ですか、それともスキャンを 1 回のパスで実行できますか?

コマンド ライン呼び出し ( 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;
}

ここが懸念事項です。私のコードでは、文字列をスキャンし、データのブロックを取得したら、その部分をスキャンして、配列に入力する辞書を作成しています。これは事実上、ストリングが 2 回歩くことを意味します。これは 15 ~ 30 秒ごとに発生し、数百のジョブが含まれる可能性があるため、CPU とメモリを大量に消費する可能性があり、これを実行しているアプリが Compressor アプリ (つまりすでにメモリと CPU を食い尽くしています) - 必要がなければ負担を増やしたくありません。

データを取得するために NSScanner を使用するより良い方法はありますか?

アドバイスや推奨事項は大歓迎です!

4

1 に答える 1

1

jobScanner がスキャンした jobStatus を使用して detailScanner を構築しているという点で、ネストは問題ありません。それは問題ではありません。ただし、他に 2 つあります。1 つは、空白文字に汗をかきすぎていることですが、それよりも悪いことに、最初の 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 に答える