5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[JavaScript] Unicode 文字列やバイナリデータを Base64 エンコードおよびデコードする

Last updated at Posted at 2023-03-08

JavaScript には Base64 エンコードするための btoa 関数が用意されていますが、挙動が少し特殊で、単純に Unicode 文字列を渡すとエラーが発生し、また、ArrayBufferTypedArray を直接渡すことができません。

そのため、Unicode 文字列やバイナリデータを btoa 関数で扱える状態に変換してから btoa 関数で Base64 エンコードします。

参考「btoa() - Web API | MDN

デコードを行う atob 関数に関しても同様の逆の変換が必要です。

参考「atob() - Web API | MDN

1. バイナリデータの場合

Unicode 文字列も結果的にバイナリデータとして扱うため、バイナリデータを Base64 エンコードする方法を先に説明します。

1.1. Base64 エンコード

Base64 エンコード を行う btoa 関数は文字列を引数として渡しますが、その文字列の文字 1 つ 1 つを 1 バイトのデータとみなします (JavaScript の文字列の文字自体は 2 バイトです) 。

そのため、例えば Uint8Array であればその各要素を各文字に割り当てた文字列に変換すれば btoa 関数に渡すことができます (1 バイトずつに 1 バイトのデータが入っている状態から 2 バイトずつに 1 バイトのデータが入っている状態に変換する) 。

文字コードを文字として扱うために String.fromCharCode を用いて変換します。

バイナリデータを Base64 エンコード
const decodeBinaryString = uint8Array => uint8Array.reduce(
	(binaryString, uint8) => binaryString + String.fromCharCode(uint8),
	'',
);

// 
const uint8ArrayA = new Uint8Array([0x00, 0x10, 0x20, 0x30]);
console.log(uint8ArrayA.toString());

const binaryStringA = decodeBinaryString(uint8ArrayA);
const base64 = btoa(binaryStringA);
console.log(base64);
実行結果
0,16,32,48
ABAgMA==

ArrayBuffer のデータを Base64 エンコードしたい場合は Uint8Array に変換します。

const arrayBufferA = new Uint16Array([0x1000, 0x3020]).buffer;
const uint8ArrayA = new Uint8Array(arrayBufferA);
console.log(uint8ArrayA.toString());

1.2. Base64 デコード

Base64 デコードする場合は文字として扱っているバイトを本来のバイト列に戻します (2 バイトずつに 1 バイトのデータが入っている状態から 1 バイトずつに 1 バイトのデータが入っている状態に変換する) 。

文字を文字コードに変換するために String.prototype.charCodeAt を使用します。

Base64 デコードは atob 関数で行います。

バイナリデータを Base64 デコード
const encodeBinaryString = binaryString => Uint8Array.from(
	binaryString,
	binaryChar => binaryChar.charCodeAt(0),
);

// 
const base64 = 'ABAgMA==';
console.log(base64);

const binaryStringB = atob(base64);
const uint8ArrayB = encodeBinaryString(binaryStringB);
console.log(uint8ArrayB.toString());
実行結果
ABAgMA==
0,16,32,48

参考「TypedArray.from() - JavaScript | MDN

2. Unicode 文字列の場合

2.1. Base64 エンコード

前述の通り JavaScript で扱う文字列の文字は 2 バイトのため、btoa 関数の仕様から、日本語等を含む Unicode 文字列を直接 btoa 関数に渡すとエラーが発生します。

TextEncoder.prototype.encode を用いて Uint8Array に変換することで、Unicode 文字列をバイナリデータとして Base64 エンコードすることができます。

Unicode 文字列を Base64 エンコード
const textEncoder = new TextEncoder();
const encodeString = string => textEncoder.encode(string);

const decodeBinaryString = uint8Array => uint8Array.reduce(
	(binaryString, uint8) => binaryString + String.fromCharCode(uint8),
	'',
);

// 
const stringA = 'Unicode 文字列';
console.log(stringA);

const uint8ArrayA = encodeString(stringA);
const binaryStringA = decodeBinaryString(uint8ArrayA);
const base64 = btoa(binaryStringA);
console.log(base64);
実行結果
Unicode 文字列
VW5pY29kZSDmloflrZfliJc=

2.2. Base64 デコード

Base64 デコードする場合は TextDecoder.prototype.decode を用いて Uint8Array から Unicode 文字列に戻します。

Unicode 文字列を Base64 デコード
const textDecoder = new TextDecoder();
const decodeString = buffer => textDecoder.decode(buffer);

const encodeBinaryString = binaryString => Uint8Array.from(
	binaryString,
	binaryChar => binaryChar.charCodeAt(0),
);

// 
const base64 = 'VW5pY29kZSDmloflrZfliJc=';
console.log(base64);

const binaryStringB = atob(base64);
const uint8ArrayB = encodeBinaryString(binaryStringB);
const stringB = decodeString(uint8ArrayB);
console.log(stringB);
実行結果
VW5pY29kZSDmloflrZfliJc=
Unicode 文字列

3. escape および unescape を用いる方法は非推奨

Unicode 文字列を扱う場合の btoa 関数のエラー対策として escape および unescape を用いる方法がありますが、escape および unescape 自体が非推奨になっているため使用しない方が良いです。

(ちなみに実行結果自体は前述の方法と一致するため、「エンコード結果が異なること」が非推奨な理由ではないです。)

Unicode 文字列を Base64 エンコードおよびデコード ※非推奨のやり方
const stringA = 'Unicode 文字列';
console.log(stringA);

const binaryStringA = unescape(encodeURIComponent(stringA));
const base64 = btoa(binaryStringA);
console.log(base64);

const binaryStringB = atob(base64);
const stringB = decodeURIComponent(escape(binaryStringB));
console.log(stringB);
実行結果
Unicode 文字列
VW5pY29kZSDmloflrZfliJc=
Unicode 文字列

参考「解決策その 1 - 文字列をエンコードする前にエスケープする - Base64 - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN
参考「escape() - JavaScript | MDN
参考「unescape() - JavaScript | MDN

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?