[VBA]SJISにおける環境依存文字の自動変換

はじめに

「髙(はじごだか)」や「﨑(たつさき)」は環境依存文字としてよく例に挙げられる。
私の苗字もシステム上へ登録できないことがよくある。

ところで、ShiftJISでデータを管理しているエクセルでは文字化けを起さないのはなぜか?
ということで、ShiftJISに関してきちんと調べる。

さらに、システム上で環境依存文字を変換することはできないのかという点も確認していく。

やりたいこと

  1. エクセルにおけるShift-JISの使用可否判定処理を実装する(具体的にはJIS X 0208)。
  2. 対応する常用漢字が存在する場合(ex. 高)、それを取得、またはそれに変換する処理を実装する。

Shift-JISとは

バージョン

Shift-JISにはいくつかの規格がある。

  • JIS X 0201 [コード表※1]
    1969年リリース。
    数字、記号、カタカナからなる文字集合。まだ漢字は含まれていない。
  • JIS X 0208 [コード表※2]
    1978年リリース。1983, 1990, 1997年に改正あり。
    計6,879文字:(非漢字:524文字/漢字:第1水準2,965文字、第2水準3,390文字)
  • JIS X 0212  [コード表※3]
    1990年リリース。
    0208と完全に背反な文字を収録している。
    収録されている文字はどれもマイナーな文字ばかり。
  • JIS X 0213 [コード表※4]
    2000年リリース。2004, 2012年に改正あり。
    X 0208の完全上位互換である。(X 0208の全ての文字を含む)
    計6,879文字:(非漢字:524文字/漢字:第3水準1,259文字、第4水準2,436文字)

エクセルにおけるShift-JISの規格

「X 0201」は漢字を収録しておらず、「X 0212」はマイナーな漢字しか収録していないことから
エクセルで使用されている規格は「X 0208」or「X 0213」のいずれかであると考えられる。
次に、エクセルがそのどちらに対応しているのかを確認してみる。

まず、ネットから第1 ~ 第4水準の漢字一覧を拝借する。
続いて、各文字をシート上の関数「CODE」とVBA上で使用できる関数「Asc」に通す。

実行結果

  • CODEとAscの実行結果は「第1水準」から「第4水準」まで存在有無についていえば完全同一だった。
  • ただし、CODEはJISコードを、AscはSJISコードを返却しているため、コード値は異なる。
  • 「第1水準」「第2水準」「第4水準」は全て対応するコードを返却した。
  • 「第3水準」は1259文字のうち187文字しか変換できなかった。
    (のこりは変換不可のコード値63が返却された)

変換に失敗した187文字に共通点はあるか?

  • 文字コードの並びに関連性はあるか?
    ⇒ ない
  • 使用頻度の高い、または人名漢字などである。
    ⇒ 一見したところ、見慣れない漢字ばかり。
    ⇒ 人名漢字とも突き合せたが15文字程度しか一致しなかった。
  • X 0212に採用されている漢字である。
    ⇒ 関連性なし。
    ⇒ 変換の成功/失敗した文字集合はそれぞれ7割程度ほどX 0212の文字を含む。
  • 結論
    いずれの規格にも合致しなかった。

CP932とは

wikiを漁ってみると、「X 02nn」とは別に「CP nnn」という規格があることが分かった。
こちらもShift-JISの一種であり、マイクロソフトなどが独自に拡張した規格とのこと。
また、別名はWindows31-Jとも呼ばれるらしい。

使用できる漢字はというと、細かいところを除くと 「X 0208」の完全上位互換。(※7のWindows-31Jが符号化の対象とする文字集合)の図が分かりやすい。
また、コード一覧を確認すると、第一水準(亜~腕)と第二水準( 弌~熙)の文字コードはきちんと完全一致している。

CP932についても、Asc関数に通してみる。
すると、全ての文字に対して、対応するコードを返却できたことを確認した。(63は返却されなかった)

改めてAsc()のリファレンスページを参照するも、「この文字コードを使って」という記述が明文化されていないが、
いくつかのQAコードや私的なブログにて同様の結論に至っているようなので、これを正とする。

Shift-JISの判定処理の実装

VBAでAscを通した場合はCP932に沿って文字の有無が判定されることが分かった。
続いて、「JIS X 0208」で使用できる文字であるかを判定するにはどうしたらよいかを考える。

ASC(c) = 69 ⇔ 環境依存文字であるは成り立たないため、文字コードで具体的に絞り込んでみる。
まずそれぞれの配置は以下のとおりである。

  • 「非漢字」 :隙間はあるものの区としては第1区~第8区まで連続している。
  • 「第一水準」:第16区~第47区まで連続している。
  • 「第二水準」:第48区~第84区まで連続している。

漢字の判定処理

ここで気になる点が2つ。

  1. 各区の先頭と末尾は常に空白であるが、ここに今後文字が追加される可能性はないか。
    (もちろん、そこに追加するくらいなら空いている区を使うにきまっているが)
  2. 各区は厳密には連続しておらず、64文字分くらい空欄がある。

wikiを参照した限り、どちらも気にすることではなかった。
Shift-JISは区点番号という方式で文字を管理しており、区と区の中に納まる点がそれぞれ94個になるという仕様とのこと。
ゆえに上記1. 2.いずれに対しても文字が設定される可能性はありえないということ。

すなわち、「第一水準」(亜~腕)と「第二水準」(弌~熙)の文字コードは完全に連続していると考えてよい。
つまり、ロジック的には (889F <= Asc(c) <= 9872) or (989F <= Asc(c) <= EAA4)を満たせば「X 0208」で使用できる漢字と判断できる。

記号の判定処理

これに対して記号の処理が面倒くさい。
記号の領域は、見てくれの通り連続していない。さらに「X 0213」で第1区~第8区のいたるところに新しい記号が追加されている。
例えば、非漢字の判定を(第1区の先頭の文字コード <= Asc(c) <= 第8区の末尾の文字コード)とした場合、第4区の「」や第5区の「カ゚ 」なども
含まれてしまう。

かといって、律儀に過不足なくif文で文字コードの大小を判定しようとすると10 ~ 20個のif文が出来上がってしまって、可読性も下がるし、処理速度も下がる。
また、そもそも論で行くと、「Å 」「╂」「Ё」など、このような文字の登録を想定するシステムなどないだろうと。

そうなると話は非常に簡単で、頻出する記号、アルファベット、カタカナ、ひらがなさえくくれればそれでよい。
つまるところ、「Å 」「╂」「Ё」これらの文字はエラーにしてしまってよいだろうと。

結果的に「非漢字」の処理は以下の通り

  • 8140 (全角空白) ~ 81AC (〓)
  • 824F (0) ~  8258(9)
  • 8260 (A) ~  8279(Z)
  • 8281 (a) ~ 829A (z)
  • 829F (ぁ) ~ 82F1 (ん)
  • 8340 (ァ) ~ 8396 (ヶ)

上記の処理から漏れてしまう「非漢字」の集合は以下の通り。

∈∋⊆⊇⊂⊃∪∩∧∨¬⇒⇔∀∃∠⊥⌒∂∇≡≒≪≫√∽∝∵∫∬ʼn♯♭♪†‡¶◯
ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ
αβγδεζηθικλμνξοπρστυφχψω
АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ
абвгдеёжзийклмнопрстуфхцчшщъыьэюя
─│┌┐┘└├┬┤┴┼━┃┏┓┛┗┣┳┫┻╋┠┯┨┷┿┝┰┥┸╂

ソースコード

改めて、きちんとしたソースでShift-JIS (X 0208)の判定処理を以下に記載する。

 

参考サイト

※1 JIS X 0201 コード表
※2 JIS X 0208 コード表
※ 3 JIS X 0212 コード表
※ 4 JIS X 0213 コード表
※ 5 JIS X 0213 コード表 (第3水準漢字 1259文字)
※ 6 JIS X 0213 コード表 (第4水準漢字 2436文字)

※ 7 Microsoftコードページ932(wiki)
※ 8 CP932 コード表

※ 9 区点位置および区点番号