2009-08-29 19 views
15

Al leer un archivo NSString puedo usar initWithContentsOfFile:usedEncoding:error: y adivinará la codificación del archivo.Codificación Guess al crear un NSString desde NSData

Cuando lo creo desde un NSData aunque mi única opción es initWithData:encoding: donde tengo que pasar explícitamente la codificación. ¿Cómo puedo adivinar de manera confiable la codificación cuando trabajo con NSData en lugar de archivos?

Respuesta

12

En general, no se puede. Sin embargo, puede identificar confiablemente los archivos UTF-8: si un archivo es UTF-8 válido, no es probable que se suponga que sea otra codificación (excepto si todos los bytes están en el rango ASCII, en cuyo caso cualquier " la codificación extendida ASCII ", que incluye UTF-8, le dará el mismo resultado). Todas las codificaciones Unicode también tienen un BOM opcional que los identifica. Entonces, un enfoque razonable sería:

  • Busque una lista de materiales válida. Si hay uno, usa la codificación apropiada.
  • De lo contrario, intente interpretarlo como UTF-8. Puede hacerlo llamando al initWithData:data encoding:NSUTF8StringEncoding y verificando si el resultado es no nulo.
  • Si eso falla, use una codificación predeterminada de 8 bits, como -[NSString defaultCStringEncoding] (que proporciona una conjetura apropiada para la configuración regional).

Se es posible para tratar de mejorar la conjetura en el último paso por tratar varias codificaciones diferentes y elegir el que tiene secuencias de menor número de letras con basura en el medio, donde “basura” es cualquier carácter que es no es una letra, espacio o signo de puntuación común. Esto aumentaría significativamente la complejidad sin ser confiable en realidad.

En resumen, para poder manejar todas las codificaciones disponibles, debe hacer lo que TextEdit hace: derivar la decisión al usuario.

Una cosa más: a partir de 10.5, la codificación a menudo se almacena con un archivo en el atributo extendido com.apple.TextEncoding no documentado. Si abre un archivo con +[NSString stringWithContentsOfFile:] o similar, esto se usará automáticamente si está presente.

23

En iOS 8 y OS X 10.10 hay una nueva API en 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 

ya se puede dejar que el marco hacer la conjetura y en mi experiencia que funciona muy bien!

de la cabecera (la documentación no indica el método por el momento pero se mencionó oficialmente en WWDC Session 204 (page 270):

  1. una matriz de cadena de codificaciones sugeridas (sin especificar la tercera opción en esta lista, se consideran todas las codificaciones de cadenas pero las de la matriz tendrán una preferencia más alta, además, el orden de las codificaciones en la matriz es importante: la primera codificación tiene una preferencia mayor que la segunda en la matriz)
  2. una matriz de codificaciones de cadena que no se usarán (las codificaciones de cadena en esta lista no serán c onsidered en absoluto)
  3. una opción booleano que indica si sólo las codificaciones de cadena sugeridas son considerados
  4. una opción booleano que indica si se permite con pérdida
  5. una opción que da una cadena específica a substitude para el misterio bytes
  6. la corriente idioma del usuario
  7. una opción booleano que indica si los datos están generados por Windows

Si los valores en el diccionario tienen mal tipos (por ejemplo, el valor de NSS tringEncodingDetectionSuggestedEncodingsKey no es una matriz), se lanza una excepción.

Si los valores en el diccionario son desconocidos (por ejemplo, el valor en la matriz de codificaciones de cadena sugeridas no es una codificación válida), los valores serán ignorados.

Ejemplo (Swift):

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

Si lo que desea es la cadena decodificada y no se preocupan por la codificación se puede quitar el let encoding =

+0

parece que hay una razón por la que es no oficial todavía. Lo ejecuté con una codificación PDF NSData que devuelve -2147482362. – FireDragonMule

+0

No estoy muy seguro de si así es como funciona. Un pdf no es una cadena y este método encuentra codificaciones para cadenas de un 'NSData'. ¿Cuál es tu intención? – HAS

+0

Estoy recuperando un pdf a través de un SDK como NSData. Solo estoy teniendo problemas para mostrarlo en la vista web en este momento porque no sé cuál es la codificación o si incluso hay una codificación. – FireDragonMule