2009-12-02 127 views
8

我有一個使用NSData對象加載的二進制文件。有沒有辦法在二進制數據中找到一系列字符'abcd',並返回偏移量而不將整個文件轉換爲字符串?似乎它應該是一個簡單的答案,但我不知道該怎麼做。有任何想法嗎?在二進制數據中查找字符串

我在iOS 3上這樣做,所以我沒有-rangeOfData:options:range:可用。

我打算把這一個獎勵給Sixteen Otto來建議strstr。我去了,並找到了C函數strstr的源代碼,並將其重寫爲在一個固定長度的Byte數組上工作 - 偶爾與char數組不同,因爲它不是null結尾。這裏是我結束了代碼:

- (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

如果您的數據確實可以包含空值(原始strstr()左側太多),您爲offsetOfBytes發佈的代碼:inBuffer:ofLength:將會遇到很多問題。至少,你需要傳遞字節的長度,因爲這個函數不知道應該有多長時間。 – 2009-12-03 15:42:50

+0

嘿。感謝您的反饋。我在ofLength:參數中傳入字節的長度,所以我不確定你的意思。謝謝。 – 2009-12-03 16:15:49

+0

你傳遞了​​兩個字節的指針,但只有一個長度。這意味着你的代碼不可能知道'bytes'和'buffer'有多長,這意味着你有可能在你的搜索中結束其中一個。 – 2009-12-03 18:07:28

回答

14

將您的子到NSData對象,並使用rangeOfData:options:range:尋找那些字節在較大NSData。確保字符串編碼匹配!

在iPhone上,如果沒有,您可能必須自己做。 C函數strstr()將爲您提供指向緩衝區內第一次出現的模式的指針(只要不包含空值!),但不包含索引。下面是一個函數,應該做的工作(但是不敢保證,因爲我還沒有真正嘗試運行它...):

- (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(納米),其中n是緩衝區長度,m是子字符串的大小。它被編寫爲與NSData一起工作,原因有兩個:1)這就是您似乎手頭上的,以及2)這些對象已經封裝了實際字節和緩衝區的長度。

+1

我應該提到我在iPhone上沒有rangeofData:options:range:方法。如果它確實會是一個完美的答案。 – 2009-12-02 22:53:16

+0

很酷。我會嘗試你的代碼,看看它是如何發展的。再次感謝你的幫助。 – 2009-12-03 19:50:21

+3

更新:rangeOfData自iOS 4起可用。 – steipete 2013-01-14 13:46:02

1

如果您使用的是雪豹,一種便捷的方式是在NSData中使用新的-rangeOfData:options:range:方法,該方法返回第一次出現的數據段的範圍。否則,您可以使用其-bytes方法自己訪問NSData的內容來執行自己的搜索。

+0

好點。我沒有注意到-rangeOfData:options:range:僅在10.6中添加。 – 2009-12-02 20:07:42

+1

所以我沒有可用的方法,因爲我在iPhone上這樣做。你用什麼C函數來比較我正在尋找的字符子串到我從-bytes方法獲得的緩衝區中?有任何想法嗎? – 2009-12-02 22:54:45

1

我有同樣的問題。 與其他建議相比,我解決了這個問題。

第一,我重新格式化數據(假設你的NSData保存在var rawFile)有:

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

現在,你可以很容易做到的字符串搜索像「ABCD」或任何你想使用NSScanner類將ascii字符串傳遞給掃描儀。也許這不是很有效,但它的工作原理,直到-rangeOfData方法也可用於iPhone。

+0

感謝您的回覆。我在問題中提到的一個標準是「沒有將整個文件轉換爲字符串」,所以這對我來說不是一個可行的解決方案。現在查看我的原始問題以查看我提出的解決方案。它運行良好,根本不需要複製任何數據。我只是遍歷NSData對象中的字節,尋找我需要的字符序列,然後在找到第一次出現時返回一個指向數組中該位置的指針。 – 2009-12-03 06:53:07

+0

是的,我明白了。 真正的意義在於瞭解這種轉換的成本,我對此沒有任何線索。向蘋果請求這個...也必須開始在他們的論壇中尋找。 :-) – Andy 2009-12-10 14:05:03