Estoy tirando de datos de un sitio web a través de NSURLConnection y guardar los datos recibidos en una instancia de NSMutableData. En el connectionDidFinishLoading delegado método los datos se convierten en una cadena con una llamada a NSString del método apropiado:

NSString *result = [[NSString alloc] initWithData:data 
                                     encoding:NSUTF8StringEncoding]

La cadena resultante resulta ser un valor nulo. Si yo uso el NSASCIIStringEncoding, sin embargo, obtener la correspondiente cadena, aunque con caracteres unicode confusos como se esperaba. El servidor del Content-Type encabezado hace no especificar la codificación UTF-8, pero he intentado un número de diferentes sitios web con un escenario similar, y de allí de cadena de conversión pasa bien. Parece que el problema solo tiene que ver con la web del servicio, pero no tengo ni idea de por qué.

En una nota de lado, está tirando de las páginas web y los datos de una API de buena práctica, es decir, el almacenamiento en búfer los datos, convertir en una cadena, y la manipulación de la cadena después?

Muy apreciada!

  • Para la depuración, debe guardar los datos en un archivo en el directorio temporal si el método falla, por lo que puede abrir el archivo en TextWrangler o algo para ver lo que la codificación es en realidad.
InformationsquelleAutor dmkc | 2010-08-14

5 Comentarios

  1. 27

    Que usted dice que «es, sin duda UTF-8», pero sin un encabezado de Tipo de Contenido, realmente no se sabe que. (E incluso si lo hizo tener un encabezado que decir que, aún podría estar equivocado.)

    Mi conjetura es que sus datos es generalmente ASCII, que siempre analiza correctamente como UTF-8, pero a veces están tratando de analizar los datos que la realidad codificada en ISO 8859-1 o Windows de la página de códigos 1252. Estos datos generalmente serán en su mayoría ASCII, pero con algunos bytes fuera del rango 0-127 ASCII define. UTF-8 sería de esperar que tales bytes para formar una secuencia de unidades de código dentro de una secuencia específica de los rangos, pero en otras codificaciones, cualquier byte, independientemente de su valor, es una completa carácter en su propia. Tratando de interpretar la no-ASCII no datos de UTF-8 como codificación UTF-8 casi siempre conseguir que el equivocado resultados (error de caracteres) o ningún resultado en absoluto (no se puede decodificar; decodificador devuelve nil), debido a que los datos nunca fue codificado en UTF-8 en el primer lugar.

    Usted debe tratar de UTF-8 en primer lugar, y si falla, use ISO 8859-1. Si usted está dejando que el usuario recuperar cualquier página web, usted debe dejar que cambiar la codificación que se utiliza para descifrar los datos, en caso de que se descubra que en realidad era 8859-9 o de la página de códigos-1252 o algún otro codificación de 8 bits.

    Si usted está descargando los datos de un servidor específico, y especialmente si usted tiene influencia sobre lo que se ejecuta en el servidor, usted debe hacer una precisa encabezado de Tipo de Contenido y/o corregir cualquier error que está causando esto para servir de texto que no está en UTF-8.

    • Bien dicho. Un buen consejo de un sabio.
    • Esta es probablemente la más plena y completa respuesta. En los intereses de aquellos que siguen en mis pasos googlear para esta pregunta voy a hacer de la respuesta disponibles como la respuesta :). En resumen, parece que la decodificación como UTF, y volver a caer en otras codificaciones podría ser la mejor apuesta en caso de que algo sucede.
    • Bien, en realidad NSASCIIStringEncoding funcionaba bien como mitjak dice, pero yo creo que es una buena práctica para poner a prueba contra varias codificaciones en caso de que uno falle. Me voy a salvar lo que para mi IO clases de utilidad.
    • no trabajo en ninguna cadena que contiene todos los valores de los caracteres por encima de 127, ya que no es válido ASCII. Que debe acaba de obtener nil. En la práctica, la última vez que lo comprobé, Cacao trata de la constante como sinónimo de ISO 8859-1. Sólo puedo suponer que la razón por la que Apple no se ha arreglado esto es debido a que existen aplicaciones que dicen «ASCII» cuando quieren decir «ISO 8859-1» que iba a romper en el comportamiento correcto.
  2. 8

    Como dijo Pedro: el Encabezado de tipo de contenido es simplemente una «sugerencia» de lo que el contenido enviado se espera que sea. En el lado del servidor se puede configurar cualquier tipo de contenido y enviar secuencias de bytes, que puede ser inválida.

    Yo tenía exactamente el mismo problema relativo a las incorrecta de datos de UTF-8, que incluye ISO-8859-1 (Latin-1) caracteres (francés acentos).

    Wikipedia acerca de UTF-8 es que vale la pena leer para entender este problema y cómo manejar los errores de codificación.

    El hecho es que NSString initWithData:encoding: la aplicación estricta sólo devuelve nil cuando un error de decodificación se produce. (a diferencia de java, por ejemplo, que el uso de un carácter de sustitución)

    El pedro solución de conversión de la mayoría de los datos de UTF-8 a Latin-1 no fue satisfactorio para mí.
    (Todos los caracteres UTF-8 se vuelve incorrecta, por sólo un 1 latino carácter errático)

    Mejor opción sería una corrección en el lado del servidor, seguro, pero yo no soy responsable de este lado…

    Así que me parecían más profundos, y se encontró una solución con el uso de GNU libiconv C library (disponible en OSX y iOS)
    El principio es el uso de iconv para quitar UTF-8 caracteres no válidos (es decir, «prété» se convertirá en «prt»)

    Aquí es un código de ejemplo, el equivalente de la línea de comandos iconv -c -f UTF-8 -t UTF-8 invalid.txt > cleaned.txt

    #include "iconv.h"
    
    - (NSData *)cleanUTF8:(NSData *)data {
      iconv_t cd = iconv_open("UTF-8", "UTF-8"); //convert to UTF-8 from UTF-8
      int one = 1;
      iconvctl(cd, ICONV_SET_DISCARD_ILSEQ, &one); //discard invalid characters
    
      size_t inbytesleft, outbytesleft;
      inbytesleft = outbytesleft = data.length;
      char *inbuf  = (char *)data.bytes;
      char *outbuf = malloc(sizeof(char) * data.length);
      char *outptr = outbuf;
      if (iconv(cd, &inbuf, &inbytesleft, &outptr, &outbytesleft)
          == (size_t)-1) {
        NSLog(@"this should not happen, seriously");
        return nil;
      }
      NSData *result = [NSData dataWithBytes:outbuf length:data.length - outbytesleft];
      iconv_close(cd);
      free(outbuf);
      return result;
    }

    El resultado NSData puede ser decodificado de manera segura utilizando NSUTF8StringEncoding

    Nota de que la última iconv también permitir el retroceso de los métodos mediante el uso de :

    iconvctl(cd, ICONV_SET_FALLBACKS, &fallbacks);

    Mediante el uso de un retroceso en unicode errores, puede utilizar un carácter de sustitución, o mejor, intentar con otra codificación.
    En mi caso he conseguido el retroceso a LATIN-1 donde UTF-8 no, lo que resultó en el 99% de conversiones. Mira iconv código fuente para la comprensión de la misma.

    • No entiendo cómo usted puede simplemente descartar personajes? ¿Qué pasa si usted está tratando con cyrilics, por ejemplo? Se estaría descartando todos los personajes en su entrada.
    • Mi respuesta a la pregunta es una forma de garantizar que el texto es válido UTF-8. Es por eso que el iconv código que he publicado acaba de quitar no válido de caracteres UTF-8. Cirílico pueden ser codificados en UTF-8.. y otras codificaciones, que es fuera de tema.
    • WOW!!! GRACIAS!!! He estado golpeando mi cabeza contra la pared tratando con UTF-8 no válida que se trata de un servidor que no tengo control sobre mi NSString siempre por (null) 🙁 me gustaría ios acaba de poner bloques cuadrados o signos de interrogación o algo como Android de la clase String. Gracias de nuevo por este!!
    • por cierto, se le olvidó a free() su outbuf antes de regresar nula en el caso de error; usted podría querer arreglar para que alguien que copia + pega es no tener una pérdida de memoria (sí, sí, por serio que nunca pasará, lo sé, pero sigue siendo buena práctica). (oh, y también cerca de su iconv mango)
    • siéntase libre de editar mi respuesta 😉
    • Gracias! Acabo de tener un correo electrónico convertidos por la UCI a UTF8 en C++, pero no se puede convertir a NSString. Probé tu método funciona!

  3. 5

    La codificación por defecto de HTTP si no se especifica ninguno es ISO-8859-1. Si la respuesta HTTP es compatible con HTTP/1.1 y no especificar un conjunto de caracteres de codificación, que es la codificación que se está usando.

    Intentar descifrar la cadena con que NSISOLatin1StringEncoding.

  4. 3

    Los datos podrían haber sido en otra codificación de unicode, como UTF16, o en algunos totalmente diferentes codificaciones.

    Hay bibliotecas que se puede adivinar la codificación que se utiliza en los datos, sino que debe ser un último recurso.
    Si usted está utilizando un servicio web, que el servicio web debe tener una documentación que se dice de la codificación que se utiliza. Busca, o solicitar al proveedor del servicio web de la codificación que se utiliza. Si ninguno está disponible, usted debe tratar de obtener una muestra de datos y determinar la codificación, para que, y el uso que en el programa.

    En una nota de lado, está tirando de las páginas web y los datos de una API de buena práctica, es decir, el almacenamiento en búfer los datos, convertir en una cadena, y la manipulación de la cadena después?

    Que depende del tamaño de los datos. Si es pequeño, que estaría perfectamente bien. Si es grande, sería mejor tratar los datos por etapas.

    • Definitivamente es UTF-8. Es casi como un personaje está causando a flipar.
    • Podría publicar la cadena exacta que causa el problema? Tal vez sea incorrecto, etc.
    • Esto es tan extraño. Se comenzó a trabajar bien ahora.. he encontrado otro sitio falló en, hypem.com. Pero que ahora también funciona bien.. quiero culpar al simulador o mi red, de alguna manera, pero sinceramente, no sé.. En general, lo que podría causar un error dado que no es mi dispositivo? Podría ser un fallo de la red, posiblemente producir que, o uno de los adecuados métodos de delegado se llama en caso de un error? Gracias por pegarse alrededor de responder!
    • Supongo que los datos de la página web es a veces corruptos, debido a un error de convertir a UTF-8 para empezar, etc. Problemas de codificación son muy queridos para mí, viniendo de Japón, donde tres codificaciones competían el uno al otro. Gradual adopción de UTF8, aunque no es perfecto, es una verdadera bendición para mí.
  5. 0

    Espera un minuto, el OP es la lectura de la red en el primer lugar de la derecha? ¿por qué no utilizar NSString del
    stringWithContentsOfURL:usedEncoding:error:
    Devuelve una cadena creada por la lectura de los datos de una URL y devuelve por referencia a la codificación que se utiliza para interpretar los datos.

    + (id)stringWithContentsOfURL:(NSURL *)url usedEncoding:(NSStringEncoding *)enc error:(NSError **)error

    páginas que las páginas n reducido a una línea de je … a menos que im tristemente equivocado, por supuesto.

Dejar respuesta

Please enter your comment!
Please enter your name here