2009-12-02 5 views
8

NSDataオブジェクトを使用してロードしたバイナリファイルがあります。そのバイナリデータ内で文字列 'abcd'を検索し、ファイル全体を文字列に変換せずにオフセットを返す方法はありますか?それは簡単な答えでなければならないようですが、私はそれをどうやって行うのか分かりません。何か案は?バイナリデータで文字列を検索

私はiOS 3でこれをやっているので、-rangeOfData:options:range:は利用できません。

私はstrstrを提案するためにこれをSixteen Ottoに与えます。私は行って、C関数strstrのソースコードを見つけて、固定長のバイト配列で動作するように書き直しました。これは、ヌル終了ではないため、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]]; 
+0

offsetOfBytes:inBuffer:ofLengthのために投稿したコードは、データに実際にヌルが含まれている場合は問題が多くなります(元のstrstr()が残っています)。少なくとも、あなたはバイトの長さを渡す必要があります。なぜなら、この関数は、どれくらいの長さになっているのか分からないからです。 –

+0

ねえ。フィードバックをお寄せいただきありがとうございます。 ofLength:パラメータのバイトの長さを渡しているので、何を意味するのか分かりません。ありがとう。 –

+0

2バイトのポインタを渡していますが、長さは1つのみです。これは、あなたのコードが 'bytes'と' buffer'の両方の長さを知ることができないことを意味します。つまり、あなたの検索でそれらのどれかの終わりを逃げてしまう危険性があります。 –

答えて

14

NSDataオブジェクトへのあなたの部分文字列を変換し、rangeOfData:options:range:を使用して、より大きなNSDataに、それらのバイトを検索します。文字列エンコーディングが一致することを確認してください!

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; 
} 

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

+1

私は、rangeofData:options:range:メソッドを持たないiPhoneでこれをやっていると言わざるを得ない。それがしたら完璧な答えだろう。 –

+0

Cool。私はあなたのコードを試し、それがどうなるかを見ていきます。あなたの助けをもう一度ありがとう。 –

+3

更新:rangeOfDataはiOS 4以降で利用可能です。 – steipete

1

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

+0

良い点。私は気づいていなかった-rangeOfData:options:range:は10.6で追加されました。 –

+1

iPhoneでこれをやっているので、私はその方法を利用できません。どのようなC関数を使って、私が探している文字部分文字列を-bytesメソッドから取得したバッファと比較するのですか?何か案は? –

1

私は同じ問題を抱えていました。 私はそれを提案と比較して、それ以外のやり方で解決しました。

最初、私は(あなたのNSDataはVAR生ファイルに格納されていると仮定する)のデータを再フォーマット:今すぐ

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

、あなたは簡単に「ABCD」のような文字列検索を行うことができます。また、NSScannerクラスを使って好きなとASCII文字列をスキャナに渡します。これは本当に効率的ではないかもしれませんが、-rangeOfDataメソッドがiPhoneでも利用できるようになるまでは動作します。

+0

お返事ありがとうございます。この質問に記載されている私の基準の1つは、「ファイル全体を文字列に変換せずに」だから、これは私にとって実行可能な解決策ではありません。私の思いついた解決策を見るために今私の元の質問をチェックしてください。データをまったくコピーする必要はありません。 NSDataオブジェクトのバイトを繰り返して、必要な文字シーケンスを探して、最初のオカレンスを見つけたら配列のその位置へのポインタを返します。 –

+0

はいわかります。 本当のポイントは、このような変換のコストを理解することです、私は本当にこれに手掛かりを持っていません。 Appleにこれを聞くことは有益かもしれません...彼らのフォーラムでも見ていなければなりません。 :-) – Andy