8

我有一个使用 NSData 对象加载的二进制文件。有没有办法在二进制数据中定位一系列字符,例如“abcd”并返回偏移量而不将整个文件转换为字符串?似乎这应该是一个简单的答案,但我不知道该怎么做。有任何想法吗?

我在 iOS 3 上这样做,所以我没有-rangeOfData:options:range:

我将把这个奖励给 16 奥托,因为他建议了 strstr。我找到了 C 函数 strstr 的源代码,并将其重写为在固定长度的 Byte 数组上工作——顺便说一下,它与 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对象,并NSData使用rangeOfData:options:range:. 确保字符串编码匹配!

在 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(nm) 中运行,其中 n 是缓冲区长度,m 是子字符串的大小。编写它的NSData原因有两个: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];

现在,您可以使用 NSScanner 类轻松地进行字符串搜索,如“abcd”或任何您想要的,并将 ascii 字符串传递给扫描仪。也许这不是很有效,但在 iPhone 也可以使用 -rangeOfData 方法之前它一直有效。

于 2009-12-03T01:29:05.873 回答