Estoy creando una aplicación de JavaScript que recupera archivos .json con jquery e inyecta datos en la página web en la que está incrustado.
Los archivos .json están codificados con UTF-8 y contienen caracteres acentuados como é, ö y å.
El problema es que no controlo el juego de caracteres en las páginas que van a usar la aplicación.
Algunos usarán UTF-8, pero otros usarán el juego de caracteres iso-8859-1. Por supuesto, esto distorsionará los caracteres especiales de los archivos .json .
¿Cómo convierto caracteres UTF-8 especiales a su equivalente iso-8859-1 usando javascript?
En realidad, todo se almacena típicamente como Unicode de algún tipo internamente, pero no entremos en eso. Supongo que está obteniendo las icónicas cadenas de tipo "åäö" porque está usando un ISO-8859 como codificación de caracteres. Hay un truco que puedes hacer para convertir esos caracteres. Las funciones de escape y anulación de unescape utilizadas para codificar y decodificar cadenas de consulta están definidas para caracteres ISO, mientras que las nuevas encodeURIComponent y decodeURIComponent , que hacen lo mismo, están definidas para caracteres UTF8.
escape codifica caracteres ISO-8859-1 extendidos (puntos de código UTF U+0080-U+00ff) como %xx (hexadecimal de dos dígitos) mientras que codifica puntos de código UTF U+0100 y superiores como %uxxxx ( %u seguido de cuatro dígitos). dígito hexadecimal). Por ejemplo, escape("å") == "%E5" y escape("あ") == "%u3042" .
encodeURIComponent codifica por ciento los caracteres extendidos como una secuencia de bytes UTF8. Por ejemplo, encodeURIComponent("å") == "%C3%A5" y encodeURIComponent("あ") == "%E3%81%82" .
Entonces puedes hacer:
fixedstring = decodeURIComponent(escape(utfstring)); Por ejemplo, un carácter codificado incorrectamente "å" se convierte en "Ã¥". El comando se escape("Ã¥") == "%C3%A5" , que son los dos caracteres ISO incorrectos codificados como bytes individuales. Luego decodeURIComponent("%C3%A5") == "å" , donde los dos bytes codificados en porcentaje se interpretan como una secuencia UTF8.
Si necesita hacer lo contrario por alguna razón, eso también funciona:
utfstring = unescape(encodeURIComponent(originalstring));¿Hay alguna manera de diferenciar entre cadenas UTF8 malas y cadenas ISO? Resulta que hay. La función decodeURIComponent utilizada anteriormente generará un error si se le proporciona una secuencia codificada con formato incorrecto. Podemos usar esto para detectar con mucha probabilidad si nuestra cadena es UTF8 o ISO.
var fixedstring; try{ // If the string is UTF-8, this will work and not throw an error. fixedstring=decodeURIComponent(escape(badstring)); }catch(e){ // If it isn't, an error will be thrown, and we can assume that we have an ISO string. fixedstring=badstring; }El problema es que una vez que se muestra la página, el contenido estará en la codificación descrita en la metaetiqueta de tipo de contenido. El contenido en codificación "incorrecta" ya está distorsionado.
Lo mejor es hacer esto en el servidor antes de publicar la página. O como se me suele decir: UTF-8 de extremo a extremo o morir .
Dado que la pregunta sobre cómo convertir de ISO-8859-1 a UTF-8 está cerrada debido a esto, voy a publicar mi solución aquí.
El problema es cuando intenta OBTENER algo usando XMLHttpRequest, si XMLHttpRequest.responseType es "texto" o está vacío, XMLHttpRequest.response se transforma en DOMString y ahí es donde las cosas se rompen. Después, es casi imposible trabajar de manera confiable con esa cadena.
Ahora, si el contenido del servidor es ISO-8859-1, deberá forzar que la respuesta sea del tipo " Blob " y luego convertirlo a DOMSTring. Por ejemplo:
var ajax = new XMLHttpRequest(); ajax.open('GET', url, true); ajax.responseType = 'blob'; ajax.onreadystatechange = function(){ ... if(ajax.responseType === 'blob'){ // Convert the blob to a string var reader = new window.FileReader(); reader.addEventListener('loadend', function() { // For ISO-8859-1 there's no further conversion required Promise.resolve(reader.result); }); reader.readAsBinaryString(ajax.response); } }Parece que la magia está sucediendo en readAsBinaryString , por lo que tal vez alguien pueda arrojar algo de luz sobre por qué funciona.