2009-08-29 5 views
15

Lors de la lecture d'un NSString à partir d'un fichier, je peux utiliser initWithContentsOfFile:usedEncoding:error: et il devinera l'encodage du fichier.Encoder le codage lors de la création d'un NSString à partir de NSData

Lorsque je le crée à partir d'un NSData bien que ma seule option est initWithData:encoding: où je dois passer explicitement l'encodage. Comment puis-je deviner l'encodage de manière fiable lorsque je travaille avec NSData au lieu de fichiers?

Répondre

12

En général, vous ne pouvez pas. Cependant, vous pouvez identifier de manière fiable les fichiers UTF-8 - si un fichier est UTF-8 valide, il est peu probable qu'il soit supposé être un autre encodage (sauf si tous les octets sont dans la plage ASCII, auquel cas le codage ASCII étendu, y compris UTF-8, vous donnera le même résultat). Tous les encodages Unicode ont également un BOM optionnel qui les identifie. Une approche raisonnable serait donc:

  • Recherchez une nomenclature valide. S'il y en a un, utilisez l'encodage approprié.
  • Sinon, essayez de l'interpréter comme UTF-8. Vous pouvez le faire en appelant initWithData:data encoding:NSUTF8StringEncoding et en vérifiant si le résultat est non-nul.
  • Si cela échoue, utilisez un codage 8 bits par défaut, tel que -[NSString defaultCStringEncoding] (qui fournit une estimation appropriée aux paramètres régionaux).

Il est possible d'essayer d'améliorer la conjecture dans la dernière étape en essayant différents encodages différents et choisir celui qui a le moins de séquences de lettres avec l'ordure au milieu, où « junk » est un caractère qui est pas une lettre, un espace ou un signe de ponctuation commun. Cela augmenterait considérablement la complexité sans être réellement fiable.

En bref, pour pouvoir gérer tous les encodages disponibles, vous devez faire ce que fait TextEdit: transférer la décision à l'utilisateur.

Oh, encore une chose: dès 10.5, l'encodage est souvent stocké avec un fichier dans l'attribut étendu com.apple.TextEncoding non documenté. Si vous ouvrez un fichier avec +[NSString stringWithContentsOfFile:] ou similaire, il sera automatiquement utilisé s'il est présent.

23

Dans iOS 8 et OS X 10,10 il y a une nouvelle API sur 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 

Maintenant vous pouvez laisser la cadre faire la conjecture et dans mon expérience qui fonctionne très bien!

De l'en-tête (la documentation ne précise pas la méthode pour le moment mais il a été officiellement mentionné dans WWDC Session 204 (page 270):

  1. un tableau de codages de chaîne proposées (sans spécifier la 3ème option dans cette liste, tous les encodages de chaînes sont pris en compte, mais ceux du tableau auront une préférence plus élevée, de plus, l'ordre des encodages dans le tableau est important: le premier encodage a une préférence plus grande que le second)
  2. des encodages de chaînes à ne pas utiliser (les encodages de chaînes dans cette liste ne seront pas c onsidered du tout)
  3. une option booléenne indiquant si seulement les codages de chaînes proposées sont considérées comme
  4. une option booléenne indiquant si lossy est autorisé
  5. une option qui donne une chaîne spécifique à substitude pour le mystère octets
  6. le courant la langue de l'utilisateur
  7. une option booléenne indiquant si les données sont générées par Windows

Si les valeurs dans le dictionnaire ont mauvais types (par exemple, la valeur de NSS tringEncodingDetectionSuggestedEncodingsKey n'est pas un tableau), une exception est levée.

Si les valeurs dans le dictionnaire sont inconnues (par exemple, la valeur dans le tableau des codages de chaîne suggérés n'est pas un codage valide), les valeurs seront ignorées.

Exemple (Swift):

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

Si vous voulez juste la chaîne décodée et ne se soucient pas de l'encodage, vous pouvez retirer le let encoding =

+0

On dirait qu'il ya une raison pour laquelle il est pas encore officiel. Je l'ai couru avec un encodage PDF NSData il retourne -2147482362. – FireDragonMule

+0

Je ne suis pas tout à fait sûr si c'est comme cela que c'est prévu pour fonctionner. Un pdf n'est pas une chaîne et cette méthode trouve des encodages pour les chaînes à partir d'un 'NSData'. Quelle est votre intention? – HAS

+0

Je récupère un pdf à travers un SDK comme NSData. Je n'ai que des problèmes d'affichage dans le webview parce que je ne sais pas quel est le codage ou s'il y a même un encodage. – FireDragonMule

Questions connexes