web-dev-qa-db-ja.com

javascriptを使用して特別なUTF-8文字をiso-8859-1相当に変換するにはどうすればよいですか?

Jqueryで.jsonファイルを取得し、埋め込まれているWebページにデータを挿入するjavascriptアプリを作成しています。

.jsonファイルはUTF-8でエンコードされ、é、ö、åなどのアクセント付き文字が含まれています。

問題は、アプリを使用するページの文字セットを制御しないことです。

UTF-8を使用するものもあれば、iso-8859-1文字セットを使用するものもあります。もちろん、これは.jsonファイルからの特殊文字を文字化けします。

Javascriptを使用して特別なUTF-8文字をiso-8859-1相当に変換するにはどうすればよいですか?

50
Hobhouse

実際には、すべては通常、何らかの種類のUnicodeとして内部的に保存されますが、その中に入ることはできません。文字エンコードとしてISO-8859を使用しているため、象徴的な「åäö」タイプの文字列を取得していると想定しています。これらの文字を変換するためにできるトリックがあります。クエリ文字列のエンコードおよびデコードに使用されるescapeおよびunescape関数はISO文字に対して定義されていますが、新しいencodeURIComponentおよびdecodeURIComponentは同じことを行い、 UTF8文字に対して定義されています。

escapeは、拡張ISO-8859-1文字(UTFコードポイントU + 0080-U + 00ff)を%xx(2桁の16進数)としてエンコードしますが、UTFコードポイントU + 0100以降は%uxxxx%uの後に続く4桁の16進数。)たとえば、escape("å") == "%E5"およびescape("あ") == "%u3042"

encodeURIComponentは、拡張文字をUTF8バイトシーケンスとしてパーセントエンコードします。たとえば、encodeURIComponent("å") == "%C3%A5"およびencodeURIComponent("あ") == "%E3%81%82"などです。

だからあなたができる:

fixedstring = decodeURIComponent(escape(utfstring));

たとえば、誤ってエンコードされた文字「å」は「Ã¥」になります。このコマンドは、escape("Ã¥") == "%C3%A5"を実行します。これは、シングルバイトとしてエンコードされた2つの不正なISO文字です。次に、decodeURIComponent("%C3%A5") == "å"で、2つのパーセントエンコードされたバイトがUTF8シーケンスとして解釈されます。

何らかの理由で逆の操作を行う必要がある場合、それも機能します。

utfstring = unescape(encodeURIComponent(originalstring));

不正なUTF8文字列とISO文字列を区別する方法はありますか?あることが判明。上記で使用したdecodeURIComponent関数は、不正な形式のエンコードされたシーケンスが指定された場合、エラーをスローします。これを使用して、文字列がUTF8か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;
}
136
nitro2k01

問題は、ページが提供されると、コンテンツがcontent-typeメタタグに記述されたエンコーディングになることです。 「間違った」エンコーディングのコンテンツはすでに文字化けしています。

ページでサービスを提供する前に、サーバーでこれを行うのが最善です。または、私が言うことがわかっているように:TF-8エンドツーエンドまたはダイ

ISO-8859-1からUTF-8への変換方法に関する question はこのため閉鎖されているため、ここにソリューションを投稿します。

問題は、XMLHttpRequestを使用して何かを取得しようとすると、XMLHttpRequest.responseTypeが「text」または空の場合、XMLHttpRequest.responseがDOMStringに変換され、それが分割されることです。その後、その文字列を確実に使用することはほとんど不可能です。

現在、サーバーからのコンテンツがISO-8859-1である場合、応答のタイプを「 Blob 」にし、後でこれをDOMSTringに変換する必要があります。例えば:

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);
    }
}

魔法がreadAsBinaryStringで起こっているように思えるので、誰かがこれがなぜ機能するかについていくらかの光を当てることができるかもしれません。

2
Eldelshell

内部的には、JavaScript文字列はすべてUnicode(実際にはUTF-16のサブセットであるUCS-2)です。

JSONファイルをAJAX経由で個別に取得する場合、JSONファイルが正しいContent-Typeと文字セットで提供されることを確認する必要があるだけです:Content-Type: application/json; charset="utf-8")。そうすれば、デシリアライズされたオブジェクトにアクセスするまでに、jQueryはすでにそれらを適切に解釈しているはずです。

JSONオブジェクトを取得するために使用しているコードの例を投稿できますか?

1
Martijn