У вас может быть библиотека JAR, скомпилированная в Java 7, и у вас есть только Java 6 как Java Runtime. Это может случиться с некоторыми новыми библиотеками.
В Mozilla MDN есть замечательная статья , которая описывает именно эту проблему:
«Проблема Unicode» Поскольку DOMStrings - это строки с 16-битным кодированием, в большинстве браузеры, вызывающие window.btoa в строке Unicode, вызывают исключение Character Out Of Range, если символ превышает диапазон 8-разрядного символа в кодировке ASCII. Существует два возможных способа решения этой проблемы:
- первым из них является выход из всей строки, а затем ее кодирование,
- , второй - преобразование UTF- 16 DOMString в массив символов UTF-8 и затем кодировать его.
Примечание к исходному ответу: ранее в статье MDN было предложено использовать
unescape
иescape
для решения проблемы исключенияCharacter Out Of Range
, но с тех пор они устарели. Некоторые другие ответы здесь предложили обойти это с помощьюdecodeURIComponent
иencodeURIComponent
, это оказалось ненадежным и непредсказуемым.В конце концов, вы определенно могли бы сэкономить некоторое горе с помощью библиотеки:
Вот текущая рекомендация, прямо из MDN, с некоторой дополнительной совместимостью TypeScript через @ MA-Maddin:
Кодирование UTF8 ⇢ base64
Реализовать регулярное выражение вместо устаревшей функции unescape
function b64EncodeUnicode(str) { return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) { return String.fromCharCode(parseInt(p1, 16)) })) } b64EncodeUnicode('✓ à la mode') // "4pyTIMOgIGxhIG1vZGU=" b64EncodeUnicode('\n') // "Cg=="
Декодирование base64 ⇢ UTF8
В статье MDN изначально не был пример для декодирования, но теперь добавлено
function b64DecodeUnicode(str) { return decodeURIComponent(Array.prototype.map.call(atob(str), function(c) { return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2) }).join('')) } b64DecodeUnicode('4pyTIMOgIGxhIG1vZGU=') // "✓ à la mode" b64DecodeUnicode('Cg==') // "\n"
Исходное решение (устарело)
Это использовало
escape
иunescape
(которые теперь устарели, хотя это все еще работает во всех современных браузерах):function utf8_to_b64( str ) { return window.btoa(unescape(encodeURIComponent( str ))); } function b64_to_utf8( str ) { return decodeURIComponent(escape(window.atob( str ))); } // Usage: utf8_to_b64('✓ à la mode'); // "4pyTIMOgIGxhIG1vZGU=" b64_to_utf8('4pyTIMOgIGxhIG1vZGU='); // "✓ à la mode"
И последнее: впервые я столкнулся с этой проблемой при вызове API GitHub. Чтобы заставить это работать на (Mobile) Safari должным образом, я фактически должен был удалить все пустое пространство от источника base64 до , я мог бы даже декодировать источник. Является ли это еще актуальным в 2017 году, я не знаю:
function b64_to_utf8( str ) { str = str.replace(/\s/g, ''); return decodeURIComponent(escape(window.atob( str ))); }
Вот некоторые будущие коды для браузеров, которые могут отсутствовать escape/unescape()
. Обратите внимание, что IE 9 и старше не поддерживают atob/btoa()
, поэтому вам нужно будет использовать для них пользовательские функции base64.
// Polyfill for escape/unescape
if( !window.unescape ){
window.unescape = function( s ){
return s.replace( /%([0-9A-F]{2})/g, function( m, p ) {
return String.fromCharCode( '0x' + p );
} );
};
}
if( !window.escape ){
window.escape = function( s ){
var chr, hex, i = 0, l = s.length, out = '';
for( ; i < l; i ++ ){
chr = s.charAt( i );
if( chr.search( /[A-Za-z0-9\@\*\_\+\-\.\/]/ ) > -1 ){
out += chr; continue; }
hex = s.charCodeAt( i ).toString( 16 );
out += '%' + ( hex.length % 2 != 0 ? '0' : '' ) + hex;
}
return out;
};
}
// Base64 encoding of UTF-8 strings
var utf8ToB64 = function( s ){
return btoa( unescape( encodeURIComponent( s ) ) );
};
var b64ToUtf8 = function( s ){
return decodeURIComponent( escape( atob( s ) ) );
};
Более полным примером кодировки и декодирования UTF-8 может быть найдено здесь: http://jsfiddle.net/47zwb41o/
Малая коррекция, unescape и escape устарели, поэтому:
function utf8_to_b64( str ) {
return window.btoa(decodeURIComponent(encodeURIComponent(str)));
}
function b64_to_utf8( str ) {
return decodeURIComponent(encodeURIComponent(window.atob(str)));
}
function b64_to_utf8( str ) {
str = str.replace(/\s/g, '');
return decodeURIComponent(encodeURIComponent(window.atob(str)));
}
encodeURIComponent
является инверсией decodeURIComponent
, т. Е. Просто отменяет преобразование. См. stackoverflow.com/a/31412163/1534459 для подробного объяснения того, что происходит с escape
и unescape
.
– bodo
1 February 2016 в 15:50
encodeURIComponent
, - правильно обрабатывать (весь диапазон) строк Unicode. Так, например, window.btoa(decodeURIComponent(encodeURIComponent('€')))
дает Error: String contains an invalid character
, потому что это то же самое, что window.btoa('€')
и btoa
не могут кодировать €
.
– bodo
2 February 2016 в 14:47
, включая вышеописанное решение, если все еще сталкиваются с проблемой, попробуйте, как показано ниже, рассмотрите случай, когда escape не поддерживается для TS.
blob = new Blob(["\ufeff", csv_content]); // this will make symbols to appears in excel
для csv_content вы можете попробовать, как показано ниже.
function b64DecodeUnicode(str: any) {
return decodeURIComponent(atob(str).split('').map((c: any) => {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
}
Если обрабатывать строки как байты - это больше, вы можете использовать следующие функции
function u_atob(ascii) {
return Uint8Array.from(atob(ascii), c => c.charCodeAt(0));
}
function u_btoa(buffer) {
var binary = [];
var bytes = new Uint8Array(buffer);
for (var i = 0, il = bytes.byteLength; i < il; i++) {
binary.push(String.fromCharCode(bytes[i]));
}
return btoa(binary.join(''));
}
// example, it works also with astral plane characters such as '
Вещи меняются. Методы escape / unescape устарели.
Вы можете кодировать строку URI перед кодировкой Base64. Обратите внимание, что это не кодирует кодировку UTF8 с кодировкой Base64, а скорее кодирует кодированные в кодировке Base64 данные. Обе стороны должны согласовать одну и ту же кодировку.
См. Рабочий пример здесь: http://codepen.io/anon/pen/PZgbPW
// encode string
var base64 = window.btoa(encodeURIComponent('€ 你好 æøåÆØÅ'));
// decode string
var str = decodeURIComponent(window.atob(tmp));
// str is now === '€ 你好 æøåÆØÅ'
Для проблемы с ОП должна решаться проблема сторонняя библиотека, такая как js-base64 .
b64DecodeUnicode('4pyTIMOgIGxhIG1vZGU=');
теперь корректно выводит «✓ режим la», – weeix 13 June 2016 в 06:57decodeURIComponent(atob('4pyTIMOgIGxhIG1vZGU=').split('').map(x => '%' + x.charCodeAt(0).toString(16)).join(''))
Не самый эффективный код, но это то, что есть. – daniel.gindi 5 October 2016 в 11:35