'Pencere'de' btoa 'yürütülemedi: Kodlanacak dize Latin1 aralığı dışındaki karakterler içeriyor.


133

Başlıktaki hata, testlerime göre sadece Google Chrome'da atılıyor. Base64, indirilebilmesi için büyük bir XML dosyasını kodluyorum:

this.loader.src = "data:application/x-forcedownload;base64,"+
                  btoa("<?xml version=\"1.0\" encoding=\"utf-8\"?>"
                  +"<"+this.gamesave.tagName+">"
                  +this.xml.firstChild.innerHTML
                  +"</"+this.gamesave.tagName+">");

this.loader iframe gizlidir.

Bu hata aslında oldukça değişiklik çünkü normalde, Google Chrome btoaarama üzerine çöküyordu. Mozilla Firefox'ta sorun yok, bu yüzden sorun tarayıcıyla ilgili. Dosyadaki garip karakterlerden haberim yok. Aslında ascii olmayan karakterler olmadığına inanıyorum.

S: Sorunlu karakterleri nasıl bulabilirim ve Chrome'un şikayet etmeyi bırakması için onları nasıl değiştirebilirim?

İndirmeyi başlatmak için Downloadify'ı kullanmayı denedim, ancak çalışmıyor. Güvenilir değildir ve hata ayıklamaya izin vermek için hiçbir hata atmaz.

Yanıtlar:


213

UTF8'iniz varsa, bunu kullanın (aslında SVG kaynağıyla çalışır), örneğin:

btoa(unescape(encodeURIComponent(str)))

misal:

 var imgsrc = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(markup)));
 var img = new Image(1, 1); // width, height values are optional params 
 img.src = imgsrc;

Bu base64 kodunu çözmeniz gerekiyorsa, şunu kullanın:

var str2 = decodeURIComponent(escape(window.atob(b64)));
console.log(str2);

Misal:

var str = "äöüÄÖÜçéèñ";
var b64 = window.btoa(unescape(encodeURIComponent(str)))
console.log(b64);

var str2 = decodeURIComponent(escape(window.atob(b64)));
console.log(str2);

Not: Bunu mobil safaride çalıştırmanız gerekiyorsa, tüm beyaz alanı base64 verilerinden çıkarmanız gerekebilir ...

function b64_to_utf8( str ) {
    str = str.replace(/\s/g, '');    
    return decodeURIComponent(escape(window.atob( str )));
}

2017 Güncellemesi

Bu sorun beni yine rahatsız ediyor.
Basit gerçek şu ki, atob UTF8 dizelerini gerçekten işlemiyor - yalnızca ASCII.
Ayrıca js-base64 gibi bloatware kullanmam.
Ancak webtoolkit'in küçük, güzel ve bakımı çok kolay bir uygulaması var:

/**
*
*  Base64 encode / decode
*  http://www.webtoolkit.info
*
**/
var Base64 = {

    // private property
    _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="

    // public method for encoding
    , encode: function (input)
    {
        var output = "";
        var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
        var i = 0;

        input = Base64._utf8_encode(input);

        while (i < input.length)
        {
            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);

            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;

            if (isNaN(chr2))
            {
                enc3 = enc4 = 64;
            }
            else if (isNaN(chr3))
            {
                enc4 = 64;
            }

            output = output +
                this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
                this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
        } // Whend 

        return output;
    } // End Function encode 


    // public method for decoding
    ,decode: function (input)
    {
        var output = "";
        var chr1, chr2, chr3;
        var enc1, enc2, enc3, enc4;
        var i = 0;

        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
        while (i < input.length)
        {
            enc1 = this._keyStr.indexOf(input.charAt(i++));
            enc2 = this._keyStr.indexOf(input.charAt(i++));
            enc3 = this._keyStr.indexOf(input.charAt(i++));
            enc4 = this._keyStr.indexOf(input.charAt(i++));

            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;

            output = output + String.fromCharCode(chr1);

            if (enc3 != 64)
            {
                output = output + String.fromCharCode(chr2);
            }

            if (enc4 != 64)
            {
                output = output + String.fromCharCode(chr3);
            }

        } // Whend 

        output = Base64._utf8_decode(output);

        return output;
    } // End Function decode 


    // private method for UTF-8 encoding
    ,_utf8_encode: function (string)
    {
        var utftext = "";
        string = string.replace(/\r\n/g, "\n");

        for (var n = 0; n < string.length; n++)
        {
            var c = string.charCodeAt(n);

            if (c < 128)
            {
                utftext += String.fromCharCode(c);
            }
            else if ((c > 127) && (c < 2048))
            {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else
            {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }

        } // Next n 

        return utftext;
    } // End Function _utf8_encode 

    // private method for UTF-8 decoding
    ,_utf8_decode: function (utftext)
    {
        var string = "";
        var i = 0;
        var c, c1, c2, c3;
        c = c1 = c2 = 0;

        while (i < utftext.length)
        {
            c = utftext.charCodeAt(i);

            if (c < 128)
            {
                string += String.fromCharCode(c);
                i++;
            }
            else if ((c > 191) && (c < 224))
            {
                c2 = utftext.charCodeAt(i + 1);
                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                i += 2;
            }
            else
            {
                c2 = utftext.charCodeAt(i + 1);
                c3 = utftext.charCodeAt(i + 2);
                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                i += 3;
            }

        } // Whend 

        return string;
    } // End Function _utf8_decode 

}

https://www.fileformat.info/info/unicode/utf8.htm

  • 127'ye eşit veya altındaki herhangi bir karakter için (onaltılık 0x7F), UTF-8 gösterimi bir bayttır. Tam unicode değerinin yalnızca en düşük 7 bitidir. Bu aynı zamanda ASCII değeriyle aynıdır.

  • 2047'ye eşit veya daha düşük karakterler için (onaltılık 0x07FF), UTF-8 gösterimi iki bayta yayılır. İlk bayt, iki yüksek bit setine sahip olacak ve üçüncü bit açık olacaktır (yani 0xC2 ila 0xDF). İkinci bayt, en üst bit setine sahip olacak ve ikinci bit temiz olacaktır (yani 0x80 ila 0xBF).

  • 2048'e eşit veya daha büyük ancak 65535'ten (0xFFFF) küçük tüm karakterler için UTF-8 gösterimi üç bayta yayılır.


6
bunu biraz daha açıklayabilir misin ... tamamen kayboldum
Muhammad Umer

Yerinde olsam kodu çalıştırırdım. escapedizeyi yalnızca URL geçerli karakterleri içeren dizeye dönüştürür. Bu hataları önler.
Tomáš Zato - Monica'yı yeniden etkinleştir

6
escapeve unescapeJavaScript 1.5'te kullanımdan kaldırılmıştır ve bunun yerine sırasıyla encodeURIComponentveya decodeURIComponentkullanılmalıdır. Kullanımdan kaldırılan ve yeni işlevleri birlikte kullanıyorsunuz. Neden? Bakınız: w3schools.com/jsref/jsref_escape.asp
Leif

2
@Leif: Bu tam olarak işe yarıyor çünkü kaçış ve görünmezlik hatalı (aynı şekilde);)
Stefan Steiger

8
Webpack kullanarak buraya başka kimse geldi mi?
Avindra Goolcharan

18

Kullanımı btoaile unescapeve encodeURIComponentbenim için işe yaramadı. Tüm özel karakterleri XML / HTML varlıklarıyla değiştirmek ve ardından base64 temsiline dönüştürmek, bu sorunu benim için çözmenin tek yoluydu. Bazı kodlar:

base64 = btoa(str.replace(/[\u00A0-\u2666]/g, function(c) {
    return '&#' + c.charCodeAt(0) + ';';
}));

1
Bu soruyu yayınladığımdan beri, yaptığım şeye adanmış API'ler hakkında biraz bilgi edindim. Dönüştürdüğünüz dize uzunsa, dönüştürmeyi Blobişlemek için nesneyi kullanın. Blobherhangi bir ikili veriyi işleyebilir.
Tomáš Zato -

1
IE9 hakkında emin değilim. Ama benim düşünceme göre, eğer istemci tarafı base64 dönüştürme gibi şeyler yapıyorsanız, muhtemelen er ya da geç modern özelliklere ihtiyaç duyacak modern bir web uygulaması yapıyorsunuzdur. Ayrıca, bir blob polyfill var.
Tomáš Zato -

1
@ItaloBorssatto Sen bir efsanesin!
kodepic

1
@ItaloBorssatto Benim için çalışan tek çözüm buydu. D3 svg grafiğini almak, XMLSerializer kullanarak serileştirmek, base-64 kodlu bir ASCII dizesi oluşturmak için btoa () 'ya (bu, sizin çözümünüzü kullandım) içine geçirmek ve sonra bunu görüntü elemanına geçirmek için ihtiyacım vardı. daha sonra tuvale çizin ve ardından ön uçta bir görüntüyü indirebilmeniz için dışa aktarın. Oldukça kıvrımlı ve hacky bir çözüm, ancak kullanıcılar bazı grafikleri indirmek istediklerinde sunucu tarafında oluşturulmuş grafikler gerektirmeyen bir çözüm. Eğer ilgilenirseniz size bazı kod örnekleri gönderebilirim. Yorum onlar için çok kısa
kodepic

1
@ItaloBorssatto <svg xmlns = " w3.org/2000/svg " viewBox = "0 0 1060 105" width = "1060" height = "105"> <path class = "domain" strok = "yok" d = "M -6,0.5H0.5V35.5H-6 "> <line strok =" yok "x2 =" - 6 "y1 =" 0.5 "y2 =" 0.5 "dolgu =" yok "vuruş genişliği =" 1px "yazı tipi- family = "sans-serif" font-size = "10px" /> <text fill = "rgb (196, 196, 196)" x = "- 9" y = "0.5" dy = "0.32em"> VogueEspana - Vogue España </text> <rect class = "first bar" fill = "rgb (25, 244, 71)" x = "0" y = "8" width = "790" height = "18" /> </ g> </svg> Alakasız parçaları kestim. Suçlu Vogue España -> ñ bir görüntünün tarayıcıya yüklenmesini engelledi.
kodepic

15

Bunun yerine bir kitaplık kullanın

Tekerleği yeniden icat etmemize gerek yok. Zamandan ve baş ağrısından tasarruf etmek için bir kitaplık kullanın.

js-base64

https://github.com/dankogai/js-base64 iyi ve unicode'u çok iyi desteklediğini onaylıyorum.

Base64.encode('dankogai');  // ZGFua29nYWk=
Base64.encode('小飼弾');    // 5bCP6aO85by+
Base64.encodeURI('小飼弾'); // 5bCP6aO85by-

Base64.decode('ZGFua29nYWk=');  // dankogai
Base64.decode('5bCP6aO85by+');  // 小飼弾
// note .decodeURI() is unnecessary since it accepts both flavors
Base64.decode('5bCP6aO85by-');  // 小飼弾

Bu iyi bir çözümdür, ancak btoa'nın ASCII ile sınırlı olması gibi görünse de (atob kod çözme iyi çalışıyor gibi görünse de). Bu, diğer cevapların birçoğunun işe yaramayacağından sonra benim için çalıştı. Teşekkürler!
İsim için

9

Sorunu nasıl çözdüğümü ve neden bunun doğru çözüm olduğunu düşündüğümü paylaşmam gerektiğini düşündüm (eski tarayıcı için optimize etmemeniz koşuluyla).

Verileri dataURL'ye ( data: ...) dönüştürme

var blob = new Blob(
              // I'm using page innerHTML as data
              // note that you can use the array
              // to concatenate many long strings EFFICIENTLY
              [document.body.innerHTML],
              // Mime type is important for data url
              {type : 'text/html'}
); 
// This FileReader works asynchronously, so it doesn't lag
// the web application
var a = new FileReader();
a.onload = function(e) {
     // Capture result here
     console.log(e.target.result);
};
a.readAsDataURL(blob);

Kullanıcının verileri kaydetmesine izin verme

Belirgin çözümün dışında - dataURL'nizle yeni bir pencere açarak URL olarak iki şey daha yapabilirsiniz.

1. fileSaver.js kullanın

Dosya koruyucu, önceden tanımlanmış dosya adıyla gerçek dosya kaydetme iletişim kutusu oluşturabilir. Normal dataURL yaklaşımına da geri dönebilir.

2. Kullan (deneysel) URL.createObjectURL

Bu, base64 kodlu verileri yeniden kullanmak için harikadır. DataURL'niz için kısa bir URL oluşturur:

console.log(URL.createObjectURL(blob));
//Prints: blob:http://stackoverflow.com/7c18953f-f5f8-41d2-abf5-e9cbced9bc42

Baştaki bloböneki içeren URL'yi kullanmayı unutmayın . Tekrar kullandım document.body:

görüntü açıklaması

Bu kısa URL'yi AJAX hedefi, <script>kaynak veya <a>href konumu olarak kullanabilirsiniz. Yine de URL'yi yok etmekten sorumlusunuz:

URL.revokeObjectURL('blob:http://stackoverflow.com/7c18953f-f5f8-41d2-abf5-e9cbced9bc42')

Teşekkürler dostum, günümü kurtardın :)
Sandeep Kumar

3

Stefan Steiger cevabının bir tamamlayıcısı olarak: (yorum olarak güzel görünmediği için)

String prototipini genişletme:

String.prototype.b64encode = function() { 
    return btoa(unescape(encodeURIComponent(this))); 
};
String.prototype.b64decode = function() { 
    return decodeURIComponent(escape(atob(this))); 
};

Kullanımı:

var str = "äöüÄÖÜçéèñ";
var encoded = str.b64encode();
console.log( encoded.b64decode() );

NOT:

Yorumlarda belirtildiği unescapegibi, gelecekte kaldırılabileceği için kullanılması önerilmez:

Uyarı : Unescape () kesinlikle kullanımdan kaldırılmamış olsa da ("Web standartlarından kaldırıldığı" gibi), girişinde şu ifadeler bulunan ECMA-262 standardının Ek B'sinde tanımlanmıştır:… Bu belgede belirtilen tüm dil özellikleri ve davranışları ek bir veya daha fazla istenmeyen özelliğe sahiptir ve eski kullanımın olmaması durumunda bu şartnameden çıkarılacaktır.

Not: URI'lerin kodunu çözmek için unescape kullanmayın, decodeURI veya decodeURIComponent kullanmayın bunun yerine kullanın.


6
İşlevler iyi görünüyor, ancak temel prototipleri genişletmek kötü bir uygulama.
timemachine3030

4
Javascript kötü bir uygulamadır. Bir hack daha ne, teşekkürler.
rob5408

1
@ rob5408: Prensip olarak beyanınıza katılıyorum, ancak gerçekten daha dikkatli olmalısınız: Prototipleri genişletmek jQuery'yi bozar ("sadece bir tane daha hack" ilkesini kullanan başka bir kütüphane)
Stefan Steiger

@StefanSteiger Bilmekte fayda var, anlayış için teşekkürler.
rob5408


2

btoa () yalnızca String.fromCodePoint (0) ile String.fromCodePoint (255) arasındaki karakterleri destekler. 256 veya daha yüksek bir kod noktasına sahip Base64 karakterleri için bunları önce ve sonra kodlamanız / kodunu çözmeniz gerekir.

Ve bu noktada zorlaşıyor ...

Olası her işaret bir Unicode Tablosunda düzenlenmiştir. Unicode Tablosu farklı düzlemlere (diller, matematik sembolleri vb.) Bölünmüştür. Bir uçaktaki her işaretin benzersiz bir kod noktası numarası vardır. Teorik olarak, sayı keyfi olarak büyük olabilir.

Bir bilgisayar verileri bayt (8 bit, onaltılık 0x00 - 0xff, ikili 00000000 - 11111111, ondalık 0 - 255) olarak depolar. Bu aralık normalde temel karakterleri kaydetmek için kullanılır (Latin1 aralığı).

Kod noktasından daha yüksek olan karakterler için 255 farklı kodlamalar mevcuttur. JavaScript, DOMString adlı dize olan işaret başına 16 bit (UTF-16) kullanır. Unicode, 0x10fffff'ye kadar kod noktalarını işleyebilir. Bu, birkaç biti birkaç hücre üzerinde depolamak için bir yöntemin mevcut olması gerektiği anlamına gelir.

String.fromCodePoint(0x10000).length == 2

UTF-16, iki 16 bit hücrede 20 bit depolamak için vekil çiftleri kullanır. İlk yüksek vekil 110110xxxxxxxxxx ile başlar , ikinci vekil 110111xxxxxxxxxx ile başlar . Bunun için Unicode kendi uçakları ayırdı: https://unicode-table.com/de/#high-surrogates

Karakterleri bayt (Latin1 aralığı) olarak saklamak için standart prosedürler UTF-8 kullanın .

Bunu söylediğim için üzgünüm ama bence bu işlevi kendi kendine uygulamanın başka bir yolu yok.

function stringToUTF8(str)
{
    let bytes = [];

    for(let character of str)
    {
        let code = character.codePointAt(0);

        if(code <= 127)
        {
            let byte1 = code;

            bytes.push(byte1);
        }
        else if(code <= 2047)
        {
            let byte1 = 0xC0 | (code >> 6);
            let byte2 = 0x80 | (code & 0x3F);

            bytes.push(byte1, byte2);
        }
        else if(code <= 65535)
        {
            let byte1 = 0xE0 | (code >> 12);
            let byte2 = 0x80 | ((code >> 6) & 0x3F);
            let byte3 = 0x80 | (code & 0x3F);

            bytes.push(byte1, byte2, byte3);
        }
        else if(code <= 2097151)
        {
            let byte1 = 0xF0 | (code >> 18);
            let byte2 = 0x80 | ((code >> 12) & 0x3F);
            let byte3 = 0x80 | ((code >> 6) & 0x3F);
            let byte4 = 0x80 | (code & 0x3F);

            bytes.push(byte1, byte2, byte3, byte4);
        }
    }

    return bytes;
}

function utf8ToString(bytes, fallback)
{
    let valid = undefined;
    let codePoint = undefined;
    let codeBlocks = [0, 0, 0, 0];

    let result = "";

    for(let offset = 0; offset < bytes.length; offset++)
    {
        let byte = bytes[offset];

        if((byte & 0x80) == 0x00)
        {
            codeBlocks[0] = byte & 0x7F;

            codePoint = codeBlocks[0];
        }
        else if((byte & 0xE0) == 0xC0)
        {
            codeBlocks[0] = byte & 0x1F;

            byte = bytes[++offset];
            if(offset >= bytes.length || (byte & 0xC0) != 0x80) { valid = false; break; }

            codeBlocks[1] = byte & 0x3F;

            codePoint = (codeBlocks[0] << 6) + codeBlocks[1];
        }
        else if((byte & 0xF0) == 0xE0)
        {
            codeBlocks[0] = byte & 0xF;

            for(let blockIndex = 1; blockIndex <= 2; blockIndex++)
            {
                byte = bytes[++offset];
                if(offset >= bytes.length || (byte & 0xC0) != 0x80) { valid = false; break; }

                codeBlocks[blockIndex] = byte & 0x3F;
            }
            if(valid === false) { break; }

            codePoint = (codeBlocks[0] << 12) + (codeBlocks[1] << 6) + codeBlocks[2];
        }
        else if((byte & 0xF8) == 0xF0)
        {
            codeBlocks[0] = byte & 0x7;

            for(let blockIndex = 1; blockIndex <= 3; blockIndex++)
            {
                byte = bytes[++offset];
                if(offset >= bytes.length || (byte & 0xC0) != 0x80) { valid = false; break; }

                codeBlocks[blockIndex] = byte & 0x3F;
            }
            if(valid === false) { break; }

            codePoint = (codeBlocks[0] << 18) + (codeBlocks[1] << 12) + (codeBlocks[2] << 6) + (codeBlocks[3]);
        }
        else
        {
            valid = false; break;
        }

        result += String.fromCodePoint(codePoint);
    }

    if(valid === false)
    {
        if(!fallback)
        {
            throw new TypeError("Malformed utf-8 encoding.");
        }

        result = "";

        for(let offset = 0; offset != bytes.length; offset++)
        {
            result += String.fromCharCode(bytes[offset] & 0xFF);
        }
    }

    return result;
}

function decodeBase64(text, binary)
{
    if(/[^0-9a-zA-Z\+\/\=]/.test(text)) { throw new TypeError("The string to be decoded contains characters outside of the valid base64 range."); }

    let codePointA = 'A'.codePointAt(0);
    let codePointZ = 'Z'.codePointAt(0);
    let codePointa = 'a'.codePointAt(0);
    let codePointz = 'z'.codePointAt(0);
    let codePointZero = '0'.codePointAt(0);
    let codePointNine = '9'.codePointAt(0);
    let codePointPlus = '+'.codePointAt(0);
    let codePointSlash = '/'.codePointAt(0);

    function getCodeFromKey(key)
    {
        let keyCode = key.codePointAt(0);

        if(keyCode >= codePointA && keyCode <= codePointZ)
        {
            return keyCode - codePointA;
        }
        else if(keyCode >= codePointa && keyCode <= codePointz)
        {
            return keyCode + 26 - codePointa;
        }
        else if(keyCode >= codePointZero && keyCode <= codePointNine)
        {
            return keyCode + 52 - codePointZero;
        }
        else if(keyCode == codePointPlus)
        {
            return 62;
        }
        else if(keyCode == codePointSlash)
        {
            return 63;
        }

        return undefined;
    }

    let codes = Array.from(text).map(character => getCodeFromKey(character));

    let bytesLength = Math.ceil(codes.length / 4) * 3;

    if(codes[codes.length - 2] == undefined) { bytesLength = bytesLength - 2; } else if(codes[codes.length - 1] == undefined) { bytesLength--; }

    let bytes = new Uint8Array(bytesLength);

    for(let offset = 0, index = 0; offset < bytes.length;)
    {
        let code1 = codes[index++];
        let code2 = codes[index++];
        let code3 = codes[index++];
        let code4 = codes[index++];

        let byte1 = (code1 << 2) | (code2 >> 4);
        let byte2 = ((code2 & 0xf) << 4) | (code3 >> 2);
        let byte3 = ((code3 & 0x3) << 6) | code4;

        bytes[offset++] = byte1;
        bytes[offset++] = byte2;
        bytes[offset++] = byte3;
    }

    if(binary) { return bytes; }

    return utf8ToString(bytes, true);
}

function encodeBase64(bytes) {
    if (bytes === undefined || bytes === null) {
        return '';
    }
    if (bytes instanceof Array) {
        bytes = bytes.filter(item => {
            return Number.isFinite(item) && item >= 0 && item <= 255;
        });
    }

    if (
        !(
            bytes instanceof Uint8Array ||
            bytes instanceof Uint8ClampedArray ||
            bytes instanceof Array
        )
    ) {
        if (typeof bytes === 'string') {
            const str = bytes;
            bytes = Array.from(unescape(encodeURIComponent(str))).map(ch =>
                ch.codePointAt(0)
            );
        } else {
            throw new TypeError('bytes must be of type Uint8Array or String.');
        }
    }

    const keys = [
        'A',
        'B',
        'C',
        'D',
        'E',
        'F',
        'G',
        'H',
        'I',
        'J',
        'K',
        'L',
        'M',
        'N',
        'O',
        'P',
        'Q',
        'R',
        'S',
        'T',
        'U',
        'V',
        'W',
        'X',
        'Y',
        'Z',
        'a',
        'b',
        'c',
        'd',
        'e',
        'f',
        'g',
        'h',
        'i',
        'j',
        'k',
        'l',
        'm',
        'n',
        'o',
        'p',
        'q',
        'r',
        's',
        't',
        'u',
        'v',
        'w',
        'x',
        'y',
        'z',
        '0',
        '1',
        '2',
        '3',
        '4',
        '5',
        '6',
        '7',
        '8',
        '9',
        '+',
        '/'
    ];
    const fillKey = '=';

    let byte1;
    let byte2;
    let byte3;
    let sign1 = ' ';
    let sign2 = ' ';
    let sign3 = ' ';
    let sign4 = ' ';

    let result = '';

    for (let index = 0; index < bytes.length; ) {
        let fillUpAt = 0;

        // tslint:disable:no-increment-decrement
        byte1 = bytes[index++];
        byte2 = bytes[index++];
        byte3 = bytes[index++];

        if (byte2 === undefined) {
            byte2 = 0;
            fillUpAt = 2;
        }

        if (byte3 === undefined) {
            byte3 = 0;
            if (!fillUpAt) {
                fillUpAt = 3;
            }
        }

        // tslint:disable:no-bitwise
        sign1 = keys[byte1 >> 2];
        sign2 = keys[((byte1 & 0x3) << 4) + (byte2 >> 4)];
        sign3 = keys[((byte2 & 0xf) << 2) + (byte3 >> 6)];
        sign4 = keys[byte3 & 0x3f];

        if (fillUpAt > 0) {
            if (fillUpAt <= 2) {
                sign3 = fillKey;
            }
            if (fillUpAt <= 3) {
                sign4 = fillKey;
            }
        }

        result += sign1 + sign2 + sign3 + sign4;

        if (fillUpAt) {
            break;
        }
    }

    return result;
}

let base64 = encodeBase64("\u{1F604}"); // unicode code point escapes for smiley
let str = decodeBase64(base64);

console.log("base64", base64);
console.log("str", str);

document.body.innerText = str;

bu nasıl kullanılır: decodeBase64(encodeBase64("\u{1F604}"))

demo: https://jsfiddle.net/qrLadeb8/


Harika çalışıyor! 🎉 görmüyorum nerede gerekmez stringToUTF8ve utf8ToStringgerçi
Benjamin Toueg

1

Bu problemle kendim karşılaştım.

İlk önce kodunuzu biraz değiştirin:

var download = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
                  +"<"+this.gamesave.tagName+">"
                  +this.xml.firstChild.innerHTML
                  +"</"+this.gamesave.tagName+">";

this.loader.src = "data:application/x-forcedownload;base64,"+
                  btoa(download);

Ardından favori web denetçinizi kullanın, this.loader.src'yi atayan kod satırına bir kesme noktası koyun, ardından şu kodu çalıştırın:

for (var i = 0; i < download.length; i++) {
  if (download[i].charCodeAt(0) > 255) {
    console.warn('found character ' + download[i].charCodeAt(0) + ' "' + download[i] + '" at position ' + i);
  }
}

Uygulamanıza bağlı olarak, verileri değiştireceğiniz için aralık dışı olan karakterleri değiştirmek işe yarayabilir veya işe yaramayabilir. Btoa yöntemiyle unicode karakterlerle ilgili MDN ile ilgili nota bakın:

https://developer.mozilla.org/en-US/docs/Web/API/window.btoa

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.