8

NSDataオブジェクトを使用してロードしたバイナリファイルがあります。そのバイナリデータ内で文字のシーケンス、たとえば「abcd」を見つけて、ファイル全体を文字列に変換せずにオフセットを返す方法はありますか?簡単な答えのようですが、どうすればいいのかわかりません。何か案は?

私はiOS3でこれを行っているので、利用できません-rangeOfData:options:range:

strstrを提案してくれたSixteenOttoにこれを授与します。私は行って、C関数strstrのソースコードを見つけ、固定長のByte配列で動作するように書き直しました。これは、nullで終了しないため、char配列とは異なります。これが私が最終的に得たコードです:

- (Byte*)offsetOfBytes:(Byte*)bytes inBuffer:(const Byte*)buffer ofLength:(int)len;
{
    Byte *cp = bytes;
    Byte *s1, *s2;

    if ( !*buffer )
        return bytes;

    int i = 0;
    for (i=0; i < len; ++i)
    {
        s1 = cp;
        s2 = (Byte*)buffer;

        while ( *s1 && *s2 && !(*s1-*s2) )
            s1++, s2++;

        if (!*s2)
            return cp;

        cp++;
    }

    return NULL;
}

これは、最初に出現するバイトへのポインタを返します。これは、バッファ内で、バイトを含む必要のあるバイト配列を探しています。

私はそれをこのように呼びます:

// data is the NSData object
const Byte *bytes = [data bytes];
Byte* index = [self offsetOfBytes:tag inBuffer:bytes ofLength:[data length]];
4

3 に答える 3

14

サブストリングをオブジェクトに変換し、を使用NSDataして大きい方のバイトを検索します。文字列のエンコーディングが一致していることを確認してください!NSDatarangeOfData:options:range:

それが利用できないiPhoneでは、これを自分で行う必要があるかもしれません。C関数strstr()は、バッファ内で最初に出現するパターンへのポインタを提供しますが(どちらにもnullが含まれていない限り)、インデックスは提供しません。これがその仕事をするはずの関数です(しかし、私は実際にそれを実行しようとしたことがないので、約束はありません...):

- (NSUInteger)indexOfData:(NSData*)needle inData:(NSData*)haystack
{
    const void* needleBytes = [needle bytes];
    const void* haystackBytes = [haystack bytes];

    // walk the length of the buffer, looking for a byte that matches the start
    // of the pattern; we can skip (|needle|-1) bytes at the end, since we can't
    // have a match that's shorter than needle itself
    for (NSUInteger i=0; i < [haystack length]-[needle length]+1; i++)
    {
        // walk needle's bytes while they still match the bytes of haystack
        // starting at i; if we walk off the end of needle, we found a match
        NSUInteger j=0;
        while (j < [needle length] && needleBytes[j] == haystackBytes[i+j])
        {
            j++;
        }
        if (j == [needle length])
        {
            return i;
        }
    }
    return NSNotFound;
}

これは、O(nm)のようなもので実行されます。ここで、nはバッファー長、mは部分文字列のサイズです。NSDataそれは2つの理由で動作するように書かれています:1)それはあなたが手にしているように見えるものであり、2)それらのオブジェクトはすでに実際のバイトとバッファの長さの両方をカプセル化しています。

于 2009-12-02T18:18:46.673 に答える
1

Snow Leopardを使用している場合、便利な方法は、NSDataの新しい-rangeOfData:options:range:メソッドでデータの最初の出現範囲を返します。それ以外の場合は、-bytesメソッドを使用してNSDataのコンテンツに自分でアクセスし、独自の検索を実行できます。

于 2009-12-02T18:29:39.100 に答える
1

私も同じ問題を抱えていました。提案と比較して、逆の方法で解決しました。

まず、データを次のように再フォーマットします (NSData が var rawFile に格納されていると仮定します)。

NSString *ascii = [[NSString alloc] initWithData:rawFile encoding:NSAsciiStringEncoding];

これで、「abcd」などの文字列検索や、NSScanner クラスを使用して任意の文字列検索を簡単に実行し、ASCII 文字列をスキャナに渡すことができます。これはあまり効率的ではないかもしれませんが、-rangeOfData メソッドが iPhone でも利用できるようになるまでは機能します。

于 2009-12-03T01:29:05.873 に答える