2009-12-02 21 views
8

NSData nesnesi kullanarak yüklediğim ikili bir dosyam var. Örneğin, bu ikili veri içinde 'abcd' karakter dizisini bulmak ve tüm dosyayı bir dizeye dönüştürmeden ofseti döndürmek için bir yol var mı? Basit bir cevap olması gerektiği gibi görünüyor, ama nasıl yapılacağından emin değilim. Herhangi bir fikir?İkili Veri İçinde Karakter Dizesi Bul

Bunu iOS 3'te yapıyorum, bu yüzden -rangeOfData:options:range: ürünüm yok.

Bunu strstr önerdiğim için Altı Otto'ya vereceğim. Ben gitti ve C işlevi strstr için kaynak kodu bulundu ve sabit bir bayt dizisi üzerinde çalışmak için yeniden yazdı - bu rastgele sonlandırılmadığı için bir char dizisinden farklıdır. Bu tampon içerisinde bayt ilk geçtiği, aradığım şey, bayt içermelidir bayt dizisi için bir işaretçi döndürür

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

: İşte ile sona erdi kodudur.

böyle diyoruz:

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

OffsetOfBytes için gönderdiğiniz kod: inBuffer: ofLength: verileriniz gerçekten boş karakterler içerebiliyorsa çok fazla sorunla karşılaşır (orijinal strstr() öğesinin çok fazlası var). En azından, bayt uzunluğundan geçmeniz gerekir, çünkü bu fonksiyonun ne kadar uzun olması gerektiği konusunda bir fikri yoktur. –

+0

Hey. Geri dönüşünüz için teşekkür ederiz. OfLength: parametresindeki baytlar için bir uzunluktan geçiyorum, bu yüzden ne demek istediğinden emin değilim. Teşekkürler. –

+0

İki bayt işaretçiden geçiyorsunuz, ancak yalnızca bir uzunluk. Bu, kodunuzun hem “bytes” hem de “buffer” kelimelerinin ne kadar sürdüğünü bilemeyeceğiniz anlamına gelir, yani aramanızdan birinin sonunu kapatmak tehlikesiyle karşı karşıya kalırsınız. –

cevap

14

bir NSData nesneye senin alt dize dönüştürme ve rangeOfData:options:range: kullanılarak NSData büyük olanlar bayt arayın. Dize kodlamalarının eşleştiğinden emin olun!

Bu, uygun olmayan yerlerde iPhone'u kendiniz yapmanız gerekebilir. strstr() C işlevi, arabellek içindeki bir şablonun ilk oluşumuna (ne null içermediği sürece!), Ancak dizini göstermez. İşte bir işlev (ı çalıştırmaya aslında denemedim beri ... ama herhangi bir söz) işi yapmak gerektiğini açıklanmıştır:

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

Bu n O (nm), gibi bir şey çalışır arabellek uzunluğu ve m, alt dizenin boyutudur. İki nedenden dolayı NSData ile çalışmak üzere yazılmıştır: 1) elinizde sahip olduğunuz şey budur, ve 2) bu nesneler zaten gerçek baytları ve arabellek uzunluğunu kapsüllemekte.

+1

Ben bunu rangeofData: options: range: method olmayan iPhone'da yaptığımı belirtmeliydim. Olsa da mükemmel bir cevap olurdu. –

+0

Serin. Kodunuzu deneyeceğim ve nasıl gittiğini göreceğim. Yardımın için tekrar teşekkürler. –

+3

Güncelleme: rangeOfData iOS 4'ten edinilebilir. – steipete

1

Eğer Snow Leopard kullanıyorsanız, yeni -rangeOfData: options: range: metodu NSData içinde bir veri parçasının ilk oluşum aralığını döndüren uygun bir yoldur. Aksi takdirde, kendi aramanızı gerçekleştirmek için NSData'nın içeriğine -bytes yöntemini kullanarak kendiniz erişebilirsiniz.

+0

İyi nokta. Bunu farketmemiştim -rangeOfData: seçenekler: aralık: sadece 10.6'da eklendi. –

+1

Bu yüzden iPhone'da bunu yaptığım için bu yönteme sahip değilim. -bytes yönteminden aldığım arabelleğe baktığım karakter alt dizisini karşılaştırmak için hangi C işlevlerini kullanırdınız? Herhangi bir fikir? –

1

Aynı problem vardı. Önerilere göre diğer yoldan bunu çözdüm. veri (sizin NSData var rawFile saklanır varsayıyorum)

ilk ben yeniden biçimlendirmek: kolayca 'abcd' ya NSScanner sınıfını kullanarak istediğiniz ne olursa olsun ve benzeri dizesini arar Şimdi

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

yapabilirsiniz ascii dizesini tarayıcıya geçirme. Belki bu gerçekten verimli değil, ama -rangeOfData yöntemi iPhone için de mevcut olacak kadar çalışır.

+0

Yanıtınız için teşekkür ederiz. Soruda belirtilen kriterlerimden biri "tüm dosyayı bir dizgeye dönüştürmeden", bu benim için geçerli bir çözüm değil. Geldiğim çözümü görmek için orijinal sorumu kontrol et. Herhangi bir veri kopyalamak zorunda kalmadan iyi çalışır. İhtiyaç duyduğum karakter dizisini arayan NSData nesnesinin baytlarını yineliyorum ve ardından dizinin ilk oluşumunu bulduktan sonra bu konum için bir işaretçi döndürüyorum. –

+0

Evet görüyorum. Gerçek nokta, böyle bir dönüşümün maliyetini anlamak olurdu, bunun üzerinde gerçekten bir ipucu yok. Apple’a sormak faydalı olabilirdi ... forumlarına da bakmaya başlamalı. :-) – Andy