2009-12-02 21 views
8

Ho un file binario che ho caricato utilizzando un oggetto NSData. Esiste un modo per individuare una sequenza di caratteri, ad esempio "abcd", all'interno di quei dati binari e restituire l'offset senza convertire l'intero file in una stringa? Sembra che dovrebbe essere una risposta semplice, ma non sono sicuro di come farlo. Qualche idea?Trova stringa di caratteri in dati binari

Sto facendo questo su iOS 3 quindi non ho -rangeOfData:options:range: disponibile.

Ho intenzione di assegnare questo a Sixteen Otto per suggerire strstr. Sono andato e ho trovato il codice sorgente per la funzione C strstr e lo ho riscritto per funzionare su un array Byte a lunghezza fissa - che per inciso è diverso da un array di caratteri dato che non è terminato con null. Ecco il codice che ho finito con:

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

Ciò restituisce un puntatore alla prima occorrenza di byte, la cosa che sto cercando, in un tampone, l'array di byte che dovrebbe contenere byte.

mi chiamano così:

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

Il codice che hai postato per offsetOfBytes: inBuffer: ofLength: avrà un sacco di problemi se i tuoi dati possono davvero contenere valori nulli Per lo meno, è necessario passare la lunghezza dei byte, poiché questa funzione non ha idea di quanto tempo dovrebbe essere. –

+0

Ehi. Grazie per il feedback. Sto passando una lunghezza per i byte nel parametro ofLength :, quindi non sono sicuro di cosa intendi. Grazie. –

+0

Stai passando due puntatori di byte, ma solo una lunghezza. Ciò significa che il tuo codice non può sapere per quanto tempo sia "byte" che "buffer", il che significa che corri il pericolo di esaurire la fine di uno di essi nella ricerca. –

risposta

14

convertire il vostro stringa a un oggetto NSData, e la ricerca di tali byte nel più ampio NSData utilizzando rangeOfData:options:range:. Assicurati che le codifiche delle stringhe corrispondano!

Su iPhone, dove non è disponibile, potrebbe essere necessario farlo da soli. La funzione C strstr() ti darà un puntatore alla prima occorrenza di un modello all'interno del buffer (purché non contenga nulli!), Ma non l'indice. Ecco una funzione che dovrebbe fare il lavoro (ma nessuna promessa, visto che non ho provato di eseguirlo ...):

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

Questo viene eseguito in qualcosa di simile a O (nm), dove n è il lunghezza del buffer e m è la dimensione della sottostringa. È scritto per funzionare con NSData per due motivi: 1) è quello che sembra avere in mano, e 2) quegli oggetti incapsulano già sia i byte effettivi, sia la lunghezza del buffer.

+1

Avrei dovuto dire che lo sto facendo su iPhone che non ha il range di dati: opzioni: intervallo: metodo. Sarebbe una risposta perfetta se lo facesse comunque. –

+0

Fresco. Proverò il tuo codice e vedrò come va. Grazie ancora per il vostro aiuto. –

+3

Aggiornamento: rangeOfData è disponibile a partire da iOS 4. – steipete

1

Se si utilizza Snow Leopard, un modo conveniente è il nuovo -rangeOfData: options: range: method in NSData che restituisce l'intervallo della prima occorrenza di un dato. Altrimenti, puoi accedere ai contenuti di NSData usando il suo metodo -bytes per eseguire la tua ricerca.

+0

Buon punto. Non avevo notato che -rangeOfData: options: range: è stato aggiunto solo in 10.6. –

+1

Quindi non ho quel metodo disponibile poiché lo sto facendo su iPhone. Quali funzioni C utilizzeresti per confrontare la sottostringa di caratteri che sto cercando nel buffer che ottengo dal metodo -bytes? Qualche idea? –

1

Ho avuto lo stesso problema. L'ho risolto facendo il contrario, rispetto ai suggerimenti.

primo momento, ho riformattare i dati (dove l'NSData è memorizzato in var rawFile) con:

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

Ora, si può facilmente fare ricerche di stringhe come 'abcd' o quello che volete utilizzando la classe NSScanner e passando la stringa ascii allo scanner. Forse questo non è veramente efficiente, ma funziona fino a quando il metodo -rangeOfData sarà disponibile anche per iPhone.

+0

Grazie per la risposta. Uno dei miei criteri indicati nella domanda era "senza convertire l'intero file in una stringa", quindi questa non è una soluzione praticabile per me. Controlla la mia domanda originale ora per vedere la soluzione che ho trovato. Funziona bene senza dover copiare alcun dato. Ho solo scorrere i byte dall'oggetto NSData alla ricerca della sequenza di caratteri che mi serve e quindi restituire un puntatore a quella posizione nell'array alla ricerca della prima occorrenza. –

+0

Sì, vedo. Il punto reale sarebbe capire il costo di tale conversione, non ho davvero un indizio su questo. Potrebbe essere utile chiedere ad Apple questo ... devono iniziare a cercare nei loro forum anche. :-) – Andy