【技術MEMO】JISからSJIS,SJISからJISへの変換

文字コードの互換性問題に直面

C++のソースからC#に移植する事になったのだが、全角文字の文字コードの問題に直面した。

  • 「JISからSJISに変換」: _mbcjistojms 関数を使用
  • SJISからJISに変換」: _mbcjmstojis 関数を使用

と、ライブラリを使っているためC#のEncodingで変換すると結果が合わなかった。
互換性の為、変換処理を書いてみた。

■ JISからSJIS(_mbcjistojms)

前提条件

  • 全角文字のみ対象
  • 全角文字はエスケープされていない(2バイト単位で来る)
  • 1byte目、2byte目共に 0x21(33) ~ 0x7E(126) までが対象範囲

1byte目の変換処理

  1. 1byte目から 0x21(33) 減算後に、÷2 を実行 (端数は切り捨て)
  2. 1byte目の元の値が0x5E(94)以下の場合、1.の結果に0x81(129)を加算。それ以外の場合、1.の結果に0xC1(193)を加算。

2byte目の変換処理

  1. 1byte目の変換前の値が 0x01(1) とのANDの結果、0x01(1)か判定
  2. 1.の結果が真の場合で、さらに、2バイト目が0x5F(95)以下の場合、2バイト目に0x1F(31)を加算。それ以外の場合は、0x20(32)を加算。
  3. 1.の結果が偽の場合は、2バイト目に0x7E(126)を加算。

ソースコード(C#)

gist.github.com

SJISからJIS(_mbcjmstojis)

前提条件

  • 全角文字のみ対象
  • 1byte目は、0x81(129) ~ 0x9F(159) かつ 0xE0(224) ~ 0xEF(239)までが対象範囲。
  • 2byte目は、0x01(1) ~ 0xFE(254) までが対象範囲。(※1)

(※1) _mbcjmstojis は、2byte目が 0x00,0xFF の場合、変換しない。なんでだろ?

1byte目の変換処理

  1. 1byte目が 0xC1(193)以上か判定。
  2. 結果が真の場合
    2-1. 1byte目から0xC1(193)を減算
    2-2. 2-1.の結果を2倍にする
    2-3. 2-2の結果に0x21(33)を加算
  3. 結果が偽の場合
    3-1. 1byte目から0x81(129)を減算
    3-2. 2-1.の結果を2倍にする
    3-3. 2-2の結果に0x21(33)を加算
  4. 2byte目が、0x9F(159)以上 かつ 0xFF(255)以下の場合、0x01(1)を加算。
  5. 2byte目が、0x01(1)以上 かつ 0x1E(30)以下の場合、強制的に0xFF(255)とする。(※2)

(※2) 1byte目が、0x01(1)~0x1E(30)の場合に 0xFF(255)になっているのが良くわからん。

2byte目の変換処理

  1. 0x9E(158)以下か判定。
  2. 1.の結果が真の場合
    2-1. 0x1F(31)を減算した結果が0x60(96)を超過している場合、2バイト目から0x20(32)を減算する。
    2-2. 0x1F(31)を減算した結果が0x60(96)を超過していない場合、2バイト目から0x1F(31)を減算する。(※3)
  3. 1.の結果が偽の場合
    3-1. 2バイト目から0x7E(126)を減算する。

(※3) 2byte目が、0x01(1)~0x1E(30)の場合に、0x1F(31)を減算するとマイナスとなり桁あふれが起きる。例えば、0x01(1)の場合は、0xE2(226)となる。

ソースコード(C#)

gist.github.com