ISO-2022-JP-MSからCP932への変換

使用する機械はあまりなさそうでうけど、ISO-2022-JP-MS(JIS)からCP932(SHIFT-JIS)へ変換するコードを、以下のサイトに掲載されているプログラムを移植してみました。

http://www.geocities.jp/hoku_hoshi/TIPPRG/tipprg03.html

プログラム本体

# -*- coding: utf-8 -*-
"""
"""
# ------------------------------------------------------------------ import(s)
import sys
import array

# --------------------------------------------------------------- exception(s)
class CConvertError(Exception):
    """
    想定範囲外のJISコードエスケープを検出
    """
    pass

# ---------------------------------------------------------------- function(s)
# ============================================================================
# 0x1B([ESC]), 0x24($), 0x40(@)
# 0x1B([ESC]), 0x24($), 0x42(B)
# 0x1B([ESC]), 0x26(&), 0x40(@)
# 0x1B([ESC]), 0x28((), 0x42(B)
# 0x1B([ESC]), 0x28((), 0x4A(J)
# 0x1B([ESC]), 0x28((), 0x49(I)
def jis_to_sjis(jis_buffer):
    """
    与えられたバイト配列をJISコード文字列とみなして、SHIFT-JISへの変換を行います。

    args:
        jis_buffer (str):
            バイト配列

    returns:
        str: SHIFT-JIS文字列を戻します。
    """

    ary_src = array.array("B", jis_buffer)
    ary_dst = array.array("B")

    str_result = []

    n = 0
    kanji_mode = False
    while n < len(ary_src):
        c0 = ary_src[n]
        n += 1
        if c0 == 0x1B:
            c1 = ary_src[n]
            n += 1
            c2 = ary_src[n]
            n += 1
            if c1 == 0x24 and c2 in (0x40, 0x42):
                kanji_mode = True
            elif c1 == 0x26 and c2 == 0x40:
                kanji_mode = True
            elif c1 == 0x28 and c2 in (0x42, 0x49, 0x4A):
                kanji_mode = False
            else:
                raise CConvertError()
            continue

        if kanji_mode is True:
            c1 = ary_src[n]
            n += 1

            if c0 < 0x5F:
                irow_offset = 0x70
            else:
                irow_offset = 0xB0

            if c0 & 0x01:
                if c1 > 0x5F:
                    icell_offset = 0x20
                else:
                    icell_offset = 0x1F
            else:
                icell_offset = 0x7E

            ary_dst.append(((c0 + 1) >> 1) + irow_offset)
            ary_dst.append(c1 + icell_offset)

        else:
            ary_dst.append(c0)

    return ary_dst.tostring()


if __name__ == "__main__":

    with open("testdata.jis", "rb") as h_reader, open("testdata.conv", "wb") as h_writer:
        code_jis = h_reader.read()
        code_sjis = jis_to_sjis(code_jis)
        h_writer.write(code_sjis)
        print("cp932", code_sjis.decode("cp932"))

# [EOF]

テストデータ

ABCDE
あいうえお
FGHIJ
①②③④⑤
KLMNO
㈱㈲δ㌔㌧

テスト方法

上記の様なテストデータをUTF-8で作成して、iconvやnkfを使用してjis形式のファイルに変換します。

iconvの場合

iconv -f UTF-8 -t ISO-2022-JP-MS testdata.utf8 > testdata.jis
iconv -f UTF-8 -t CP932 > testdata.utf8 > testdata.cp932

nkfの場合

nkf -Wj testdata.utf8 > testdata.jis
nkf -Ws testdata.utf8 > testdata.cp932

.