Impossibile eseguire "btoa" su "Finestra": la stringa da codificare contiene caratteri al di fuori dell'intervallo Latin1.


133

L'errore nel titolo viene generato solo in Google Chrome, secondo i miei test. Sto codificando base64 un grande file XML in modo che possa essere scaricato:

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 nascosto.

Questo errore è in realtà un bel cambiamento perché normalmente, Google Chrome si bloccherebbe su btoachiamata. Mozilla Firefox non ha problemi qui, quindi il problema è legato al browser. Non sono a conoscenza di strani personaggi nel file. In realtà credo che non ci siano personaggi non ascii.

D: Come posso trovare i personaggi problematici e sostituirli in modo che Chrome smetta di lamentarsi?

Ho provato a utilizzare Downloadify per avviare il download, ma non funziona. È inaffidabile e non genera errori per consentire il debug.

Risposte:


212

Se hai UTF8, usa questo (in realtà funziona con il sorgente SVG), come:

btoa(unescape(encodeURIComponent(str)))

esempio:

 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;

Se devi decodificare quel base64, usa questo:

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

Esempio:

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

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

Nota: se devi farlo funzionare in mobile-safari, potresti dover rimuovere tutto lo spazio bianco dai dati base64 ...

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

Aggiornamento 2017

Questo problema mi ha infastidito di nuovo.
La semplice verità è che atob non gestisce realmente le stringhe UTF8 - è solo ASCII.
Inoltre, non userei bloatware come js-base64.
Ma webtoolkit ha un'implementazione piccola, piacevole e molto mantenibile:

/**
*
*  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

  • Per qualsiasi carattere uguale o inferiore a 127 (esadecimale 0x7F), la rappresentazione UTF-8 è un byte. Sono solo i 7 bit più bassi del valore unicode completo. Questo è anche lo stesso del valore ASCII.

  • Per caratteri uguali o inferiori a 2047 (esadecimale 0x07FF), la rappresentazione UTF-8 è distribuita su due byte. Il primo byte avrà i due bit alti impostati e il terzo bit azzerato (ovvero da 0xC2 a 0xDF). Il secondo byte avrà il bit superiore impostato e il secondo bit azzerato (cioè da 0x80 a 0xBF).

  • Per tutti i caratteri uguali o superiori a 2048 ma inferiori a 65535 (0xFFFF), la rappresentazione UTF-8 è distribuita su tre byte.


6
puoi spiegarlo un po 'di più ... sono totalmente perso
Muhammad Umer,

Avrei semplicemente eseguito il codice se fossi in te. escapeconverte la stringa in quella che contiene solo caratteri URL validi. Ciò impedisce gli errori.
Tomáš Zato - Ripristina Monica il

6
escapee unescapesono stati deprecati in JavaScript 1.5 e si dovrebbe usare encodeURIComponento decodeURIComponent, invece, rispettivamente. Stai utilizzando insieme le funzioni obsolete e nuove. Perché? Vedi: w3schools.com/jsref/jsref_escape.asp
Leif

2
@Leif: funziona solo perché fuga e unescape sono buggy (allo stesso modo);)
Stefan Steiger,

8
Qualcun altro è finito qui per l'utilizzo del webpack?
Avindra Goolcharan,

18

Usando btoacon unescapee encodeURIComponentnon ha funzionato per me. Sostituire tutti i caratteri speciali con entità XML / HTML e poi convertirli nella rappresentazione base64 è stato l'unico modo per risolvere questo problema per me. Qualche codice:

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

1
Da quando ho pubblicato questa domanda ho imparato qualcosa sulle API dedicate a ciò che stavo facendo. Se la stringa che stai convertendo è lunga, usa Blobobject per gestire la conversione. Blobpuò gestire qualsiasi dato binario.
Tomáš Zato - Ripristina Monica il

1
Non sono sicuro di IE9. Ma il mio pensiero è che se stai facendo cose come lato client di conversione base64 probabilmente stai realizzando un'app web moderna che prima o poi avrà bisogno di funzionalità moderne. Inoltre, c'è un polifill a blob.
Tomáš Zato - Ripristina Monica il

1
@ItaloBorssatto Sei una leggenda!
codeepic,

1
@ItaloBorssatto È stata l'unica soluzione che ha funzionato per me. Ne avevo bisogno per afferrare il grafico svg d3, serializzarlo usando XMLSerializer, passarlo in btoa () (è qui che ho usato la tua soluzione) per creare una stringa ASCII codificata in base 64, quindi passarlo nell'elemento immagine che è quindi disegnato su tela e quindi esportarlo in modo da poter scaricare un'immagine sul front-end. Soluzione piuttosto complicata e caotica, ma che non richiede grafici renderizzati sul lato server quando gli utenti vogliono scaricare alcuni elementi grafici. Se sei interessato, posso inviarti alcuni esempi di codice. Il commento è troppo breve per loro
codeepic

1
@ItaloBorssatto <svg xmlns = " w3.org/2000/svg " viewBox = "0 0 1060 105" width = "1060" height = "105"> <path class = "domain" stroke = "none" d = "M -6,0.5H0.5V35.5H-6 "> <line stroke =" none "x2 =" - 6 "y1 =" 0.5 "y2 =" 0.5 "fill =" none "stroke-width =" 1px "font- famiglia = "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> Ho ritagliato pezzi irrilevanti. Il colpevole è Vogue España -> ñ ha impedito il caricamento di un'immagine nel browser.
codeepic,

15

Utilizzare invece una libreria

Non dobbiamo reinventare la ruota. Basta usare una libreria per risparmiare tempo e mal di testa.

js-base64

https://github.com/dankogai/js-base64 è buono e confermo che supporta unicode molto bene.

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-');  // 小飼弾

Questa è una buona soluzione, sebbene sembri una supervisione per btoa essere limitato ad ASCII (sebbene la decodifica atob sembra funzionare bene). Questo ha funzionato per me dopo che molte altre risposte non lo avrebbero fatto. Grazie!
Per il nome

9

Ho pensato di condividere il modo in cui ho risolto il problema e perché penso che sia giusto soluzione (a condizione che non si ottimizzi per il vecchio browser).

Conversione di dati in dataURL ( data: ...)

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

Consentire all'utente di salvare i dati

Oltre alla soluzione ovvia: aprendo una nuova finestra con i tuoi datiURL come URL puoi fare altre due cose.

1. Utilizzare fileSaver.js

Il risparmiatore di file può creare una finestra di dialogo Salva file con nome file predefinito. Può anche ricorrere al normale approccio dataURL.

2. Usa (sperimentale) URL.createObjectURL

Questo è ottimo per riutilizzare i dati codificati in base64. Crea un breve URL per i tuoi datiURL:

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

Non dimenticare di utilizzare l'URL incluso il blobprefisso principale . Ho usato di document.bodynuovo:

descrizione dell'immagine

È possibile utilizzare questo breve URL come destinazione AJAX, posizione <script>sorgente o <a>href. Tuttavia, sei responsabile della distruzione dell'URL:

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

Grazie amico, mi hai salvato la giornata :)
Sandeep Kumar,

3

Come complemento alla risposta di Stefan Steiger: (in quanto non sembra carino come un commento)

Estensione del prototipo di stringa:

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

Uso:

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

NOTA:

Come indicato nei commenti, l'uso unescapenon è raccomandato poiché potrebbe essere rimosso in futuro:

Avvertenza : sebbene unescape () non sia severamente deprecato (come in "rimosso dagli standard Web"), è definito nell'Allegato B della norma ECMA-262, la cui introduzione afferma: ... Tutte le caratteristiche del linguaggio e i comportamenti specificati in questo l'allegato presenta una o più caratteristiche indesiderabili e in assenza di un uso legacy verrebbe rimosso da questa specifica.

Nota: non utilizzare unescape per decodificare gli URI, utilizzare invece decodeURI o decodeURIComponent .


6
Le funzioni sembrano buone, ma l'estensione dei prototipi di base è una cattiva pratica.
timemachine3030,

4
Javascript è una cattiva pratica. Qual è un altro trucco, grazie.
rob5408,

1
@ rob5408: Mentre sono d'accordo con la tua affermazione in linea di principio, ma dovresti davvero essere più cauto: l'estensione dei prototipi rompe jQuery (un'altra libreria che utilizza il principio "solo un altro hack")
Stefan Steiger,

@StefanSteiger Buono a sapersi, grazie per la comprensione.
rob5408,

unescapesarà presto deprecato secondo MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Akansh

2

btoa () supporta solo caratteri da String.fromCodePoint (0) fino a String.fromCodePoint (255). Per i caratteri Base64 con un punto di codice 256 o superiore, è necessario codificarli / decodificarli prima e dopo.

E a questo punto diventa complicato ...

Ogni possibile segno è organizzato in una tabella Unicode. La tabella Unicode è divisa in diversi piani (lingue, simboli matematici e così via ...). Ogni segno in un piano ha un numero di punto di codice univoco. Teoricamente, il numero può diventare arbitrariamente grande.

Un computer memorizza i dati in byte (8 bit, esadecimale 0x00 - 0xff, binario 00000000 - 11111111, decimale 0 - 255). Questo intervallo normalmente utilizza per salvare i caratteri di base (intervallo Latin1).

Per i caratteri con un punto di codice più alto allora 255 esistono codifiche diverse. JavaScript utilizza 16 bit per segno (UTF-16), la stringa chiamata DOMString. Unicode può gestire punti di codice fino a 0x10fffff. Ciò significa che deve esistere un metodo per memorizzare diversi bit su più celle di distanza.

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

UTF-16 utilizza coppie surrogate per memorizzare 20 bit in due celle a 16 bit. Il primo surrogato superiore inizia con 110110xxxxxxxxxx , il secondo inferiore con 110111xxxxxxxxxx . Unicode ha riservato i propri aerei per questo: https://unicode-table.com/de/#high-surrogates

Per memorizzare i caratteri in byte (intervallo Latin1) procedure standardizzate utilizzare UTF-8 .

Mi dispiace dirlo, ma penso che non ci sia altro modo per implementare questa funzione.

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;

come usarlo: decodeBase64(encodeBase64("\u{1F604}"))

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


Funziona alla grande! 🎉 Non vedo dove tu abbia bisogno stringToUTF8e utf8ToStringcomunque
Benjamin Toueg l'

1

Mi sono appena imbattuto in questo problema da solo.

Innanzitutto, modifica leggermente il codice:

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

Quindi utilizza il tuo ispettore web preferito, posiziona un punto di interruzione sulla riga di codice che assegna this.loader.src, quindi esegui questo codice:

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

A seconda dell'applicazione, la sostituzione dei caratteri che non rientrano nell'intervallo può o meno funzionare, poiché si modificheranno i dati. Vedi la nota su MDN sui caratteri unicode con il metodo btoa:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.