2009-08-29 19 views
15

Durante la lettura di NSString da un file, è possibile utilizzare initWithContentsOfFile:usedEncoding:error: e indovinerà la codifica del file.Codifica Guess durante la creazione di una NSString da NSData

Quando lo creo da un NSData sebbene la mia unica opzione sia initWithData:encoding: in cui devo passare esplicitamente la codifica. Come posso indovinare in modo affidabile la codifica quando lavoro con NSData anziché con i file?

risposta

12

In generale, non è possibile. Tuttavia, puoi identificare in modo affidabile i file UTF-8 - se un file è UTF-8 valido, non è molto probabile che si supponga che sia una qualsiasi altra codifica (eccetto se tutti i byte sono nell'intervallo ASCII, nel qual caso qualsiasi " codifica ASCII estesa ", incluso UTF-8, fornirà lo stesso risultato). Tutte le codifiche Unicode hanno anche un BOM opzionale che le identifica. Quindi un approccio ragionevole sarebbe:

  • Cercare una BOM valida. Se ce n'è uno, usa la codifica appropriata.
  • Altrimenti, provare a interpretarlo come UTF-8. È possibile farlo chiamando initWithData:data encoding:NSUTF8StringEncoding e controllando se il risultato non è zero.
  • Se ciò non riesce, utilizzare una codifica a 8 bit predefinita, ad esempio -[NSString defaultCStringEncoding] (che fornisce un'ipotesi appropriata per le impostazioni internazionali).

E è possibile per cercare di migliorare l'ipotesi nell'ultimo passaggio provando varie codifiche diverse e scegliendo quello che ha il minor numero di sequenze di lettere con spazzatura in mezzo, dove “spazzatura” è qualsiasi carattere che è non una lettera, uno spazio o un segno di punteggiatura comune. Ciò aumenterebbe significativamente la complessità pur non essendo effettivamente affidabile.

In breve, per essere in grado di gestire tutte le codifiche disponibili è necessario eseguire ciò che TextEdit fa: deviare la decisione all'utente.

Oh, un'altra cosa: a partire da 10.5, la codifica viene spesso archiviata con un file nell'attributo esteso com.apple.TextEncoding non documentato. Se apri un file con +[NSString stringWithContentsOfFile:] o simile, questo verrà automaticamente utilizzato se presente.

23

In iOS 8 e OS X 10.10 v'è una nuova API su NSString:

Objective-C

+ (NSStringEncoding)stringEncodingForData:(NSData *)data 
          encodingOptions:(NSDictionary *)opts 
          convertedString:(NSString **)string 
         usedLossyConversion:(BOOL *)usedLossyConversion; 

Swift

open class func stringEncoding(for data: Data, 
        encodingOptions opts: [StringEncodingDetectionOptionsKey : Any]? = nil, 
       convertedString string: AutoreleasingUnsafeMutablePointer<NSString?>?, 
        usedLossyConversion: UnsafeMutablePointer<ObjCBool>?) -> UInt 

ora è possibile lasciare che il quadro fare l'ipotesi e nella mia esperienza che funziona davvero bene!

Dal intestazione (la documentazione non indica il metodo al momento, ma è stato ufficialmente menzionato in WWDC Session 204 (page 270):

  1. una serie di codifiche stringa suggerite (senza specificare la terza opzione in questa lista, tutte le codifiche delle stringhe sono considerate ma quelle dell'array avranno una preferenza più alta, inoltre l'ordine delle codifiche nell'array è importante: la prima codifica ha una preferenza maggiore rispetto alla seconda nell'array)
  2. un array delle stringhe da non usare (le codifiche delle stringhe in questa lista non saranno c onsidered affatto)
  3. un'opzione booleano che indica se solo le codifiche stringa suggerite sono considerati
  4. un'opzione booleano che indica se lossy è consentito
  5. un'opzione che dà una stringa specifica per substitude per il mistero byte
  6. la corrente lingua dell'utente
  7. un'opzione booleano che indica se i dati sono generati da Windows

Se i valori nel dizionario hanno tipi sbagliati (per esempio, il valore di NSS tringEncodingDetectionSuggestedEncodingsKey non è una matrice), viene generata un'eccezione.

Se i valori nel dizionario sono sconosciuti (ad esempio, il valore nell'array di stringhe di stringhe suggerite non è una codifica valida), i valori verranno ignorati.

Esempio (Swift):

var convertedString: NSString? 
let encoding = NSString.stringEncoding(for: data, encodingOptions: nil, convertedString: &convertedString, usedLossyConversion: nil) 

Se si desidera solo la stringa decodificata e non si cura di codifica è possibile rimuovere il let encoding =

+0

sembra che ci sia un motivo per cui è non ancora ufficiale L'ho eseguito con una codifica PDF NSData che restituisce -2147482362. – FireDragonMule

+0

Non sono abbastanza sicuro se è così che si intende lavorare. Un pdf non è una stringa e questo metodo trova le codifiche per le stringhe da un 'NSData'. Qual è il tuo intento? – HAS

+0

Sto recuperando un pdf attraverso un SDK come NSData. In questo momento ho problemi a visualizzarlo nella webview perché non so quale sia la codifica o se esiste anche una codifica. – FireDragonMule

Problemi correlati