🪬
TypeScriptで文字列のdeflate&base64エンコード
TypeScript(JavaScript)でJSONを文字列エンコードしたくなったので実装した備忘メモです。
base64エンコード,デコード
実装
code
class Base64Codec {
#encoder: TextEncoder | undefined;
#decoder: TextDecoder | undefined;
constructor(encode: boolean = false, decode: boolean = false) {
if (encode === decode) { [encode, decode] = [true, true]; }
if (encode) { this.#encoder = new TextEncoder; }
if (decode) { this.#decoder = new TextDecoder; }
}
encode(raw: string): string {
if (this.#encoder === undefined) { return ""; }
return btoa(String.fromCodePoint(...(this.#encoder.encode(raw))));
}
decode(enc: string): string {
if (this.#decoder === undefined) { return ""; }
return this.#decoder.decode(Uint8Array.from([...atob(enc)].map(x => x.charCodeAt(0))));
}
}
使い方
const test = "Lorem ipsum dolor sit amet, consectetur adipiscing elit";
const base64 = new Base64Codec();
console.log(base64.encode(test));
// "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdA=="
console.log(base64.decode(base64.encode(test)));
// "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
簡単な解説
encode(raw: string): string {
if (this.#encoder === undefined) { return ""; }
return btoa(String.fromCodePoint(...(this.#encoder.encode(raw))));
}
-
TextEncoder
で文字列をutf8のUint8Array
に変換 -
Uint8Array
の各要素をLatin-1文字に変換 -
btoa
関数でLatin-1文字列をbase64エンコード
decode(enc: string): string {
if (this.#decoder === undefined) { return ""; }
return this.#decoder.decode(Uint8Array.from([...atob(enc)].map(x => x.charCodeAt(0))));
}
-
atob
関数でbase64符号をLatin-1文字列にデコード - Latin-1文字列の各文字を文字コードに変換
-
Uint8Array
を取得し、TextDecoder
で元の文字列取得
deflate&base64エンコード,デコード
実装
(2024/09/13追記 残念ながらCompressionStream
は使い回せないようなので関数に変更しました)
code
async function encodeDeflateString(raw: string, url: boolean = true): Promise<string> {
const enc = btoa(String.fromCodePoint(...(new Uint8Array(await new Response(new Blob([raw]).stream().pipeThrough(new CompressionStream("deflate-raw"))).arrayBuffer()))));
return url ? enc.replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "") : enc;
}
async function decodeDeflateString(enc: string, url: boolean = true): Promise<string> {
if (url) { enc = enc.replaceAll("-", "+").replaceAll("_", "/"); }
return await new Response(new Blob([Uint8Array.from([...atob(enc)].map(x => x.charCodeAt(0)))]).stream().pipeThrough(new DecompressionStream("deflate-raw"))).text();
}
使い方
async function show(raw: string, url: boolean) {
const enc = await encodeDeflateString(raw, url);
const dec = await decodeDeflateString(enc, url);
console.log(dec);
console.log(enc);
}
const raw1 = "{foo:123,bar:'234',baz:[9,8,7,6,5],qux:false}";
show(raw1, true);
// "{foo:123,bar:'234',baz:[9,8,7,6,5],qux:false}"
// "q07Lz7cyNDLWSUosslI3MjZR10lKrLKKttSx0DHXMdMxjdUpLK2wSkvMKU6tBQA"
const raw2 = "Lorem ipsum dolor sit amet, consectetur adipiscing elit";
show(raw2, false);
// "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
// "BcGBCcAwCATAVX6AjtIlgnnKQ4xBzf69eyPp0KnrmLEiUWoMZz+w2EVr9k2MqaMy7Q9c6h8="
簡単な解説
async function encodeDeflateString(raw: string, url: boolean = true): Promise<string> {
const enc = btoa(String.fromCodePoint(...(new Uint8Array(await new Response(new Blob([raw]).stream().pipeThrough(new CompressionStream("deflate-raw"))).arrayBuffer()))));
return url ? enc.replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "") : enc;
}
- 文字列をblob streamに変換
-
CompressionStream
で"deflate-raw"
圧縮 - 得られたバイト列を
Uint8Array
としてLatin-1文字列に変換 -
btoa
関数でLatin-1文字列をbase64エンコードした文字列を取得 -
url
がtrue
(URLセーフ)の場合、結果文字列をURLセーフに加工
async function decodeDeflateString(enc: string, url: boolean = true): Promise<string> {
if (url) { enc = enc.replaceAll("-", "+").replaceAll("_", "/"); }
return await new Response(new Blob([Uint8Array.from([...atob(enc)].map(x => x.charCodeAt(0)))]).stream().pipeThrough(new DecompressionStream("deflate-raw"))).text();
}
-
url
がtrue
(URLセーフ)の場合、URLセーフから通常のBase64に加工 -
atob
関数でbase64符号をLatin-1文字列にデコード - Latin-1文字列の各文字を文字コードに変換
-
Uint8Array
を取得しblob streamに変換 -
DecompressionStream
で"deflate-raw"
解凍した結果を文字列として取得
Discussion