potisanのプログラミングメモ

プログラミング素人です。昔の自分を育ててくれたネット情報に少しでも貢献できるよう、情報を貯めていこうと思っています。Windows環境のC++やC#がメインです。

JavaScript 文字列からShift-JISコード配列を取得するクラス

QiitaでTextDecoderを使ってShift-JISコードを取得する記事McbeEringi氏)を見かけました。記事中のコードは理解できていないのですが、発想を参考にShift-JISコード配列を取得するクラスを作成しました。

// UnicodeコードポイントからShift-JISへの変換機能を提供します。
// 初期化時に重い処理があります。できる限り使いまわしてください。
class SjisEncoder
{
    #sjisToCodePoint; // Uint32Array

    constructor() {
        const sjisDecoder = new TextDecoder("sjis");
        const maxSjis = 0xffff;
        this.#sjisToCodePoint = new Uint32Array(maxSjis);
        const buffer = new Uint16Array(1);
        for (let i = 0; i < this.#sjisToCodePoint.length; i++) {
            buffer[0] = i;
            this.#sjisToCodePoint[i] = sjisDecoder.decode(buffer).codePointAt(0);
        }
    }

    // コードポイントからShift-JISコードの配列を取得します。
    // 変換できない文字が含まれる場合はRangeError例外を送出します。
    codePointToSjiCodes(codepoint) {
        const i = this.#sjisToCodePoint.indexOf(codepoint);
        if (i == -1)
            throw new RangeError("コードポイントに対応するShift-JIS文字がありません。");
        // 16ビットLE→8ビット×1or2に変換
        if (i <= 0xff) return [i];
        else return [i & 0xff, (i >> 8) & 0xff];
    }

    // 文字列からShift-JISコードの配列を取得します。
    // 変換できない文字が含まれる場合はRangeError例外を送出します。
    encode(s) {
        const codepoints = Array.from(s, ch => ch.codePointAt(0));
        return codepoints.flatMap(codepoint => sjisChars.codePointToSjiCodes(codepoint));
    }
}

使用例です。

const sjisChars = new SjisEncoder();
console.log(sjisChars.encode("0123abcあいう亜位鵜㈱㍻"));
console.log(sjisChars.encode("🍊")); // 例外が発生します。

JavaScript動向を追えていないので古い書き方かもしれないことには注意してください。

蛇足です。デコーダーからエンコーダーを作る発想、脱帽しました。