oracle
文字化け
文字コード
unicode
文字Day 21

「ソ」「ソ」による文字化けについて

はじめに

これは文字 Advent Calendar 2017の21日目となります。

サーバーリプレースにて、Windows Server 2016 + Oracle12c の既存アプリケーションの導入と検証作業をしていたところ、Delphi5 + BDEを使用しているアプリケーションで、全角文字が半角カタカナの「ソ」に文字化けして表示された。その後、コマンドプロンプト上のSQL Plusで何かエラーが発生した際にも「ソ」になっていた。

ネットで検索するが、このような現象が無いのか何も見つからなかったが、別の内容で「「ソ」には特殊な意味がありますか? - Yahoo!知恵袋」で「ソ」による文字化けについて書かれていたのがあり、今回「ソ」繋がりでまとめてみた。

「ソ」よる文字化け

原因は Oracle12cはUTF-8であり、使用アプリケーションはSJISとよくある文字化けである。この場合は「?」に変換されるのが一般的と思われる。

何故、「ソ」なのだろうということで、文字コードを調べてみた。
シフトJISの1バイトコード(半角文字)のエリアマップ

また、別のアプリケーションではSQLのリテラル文字列の"登録"の文字が逆さまのクエスチョンマーク「¿」になっていた。この逆疑問符はスペイン語で使われるようです。
Latin-1 アスキーコード表 (ASCII Code Table)

文字 ASCIIコード 2進数
? 0x3F 00111111
ソ 0xBF 10111111
¿ 0xBF 10111111

最上位ビットに違いがあることが分かった。

プログラマのための文字コード技術入門」という2010年に購入した本が引っ張り出して軽く眺めてみた。
JISの8ビット符号にはGR領域とGL領域があり、GR領域を使用する場合には第8ビット(最上位ビット)に1をセットして用いるとのこと。

変換できないので「?」にして戻した後、第8ビットに1をセットする変換がされたことにより「ソ」になってしまったのではないかと推測している。
逆疑問符[¿」は「ソ」と同じコードであり、こちらはLatin-1の文字コードが使われたようだ。

ちなみに文字化けについては、環境変数に「NLS_LANG=JAPANESE_JAPAN.JA16SJISTILDE」を追加することで解消された。

「ソ」よる文字化け

Shift-JISは半角文字と全角文字を表せますが、1文字が何バイトなのかが固定されていないのです。なので「ソ」など2バイト目に5Cというコードがくる文字を使うと5CがASCIIコードで円マーク()を表すため2つの文字だと認識され、プログラムが正常に処理を行うことが出来なくなります。
「ソ」には特殊な意味がありますか? - Yahoo!知恵袋

「0x5C問題」と呼ばれるもので、「ソ」以外にも「十」「貼」「能」「表」「暴」「予」などが比較的よく使われる文字としてある。同様な問題に「ポ」もあり、こちらは7CがASCIIコードでパイプ文字(|)を表すことにより問題が発生する。
どちらも通称や俗称として「ダメ文字」とも呼ばれる。

テキスト先頭の「ソ」

文字コード「UTF-8」で保存したテキストファイルを文字コード「Shift-JIS」で開くと、何もないはずの場所に半角カタカナの「ソ」が現れます。

これはUTF-8+BOM付きで保存した際に「バイトオーダーマーク (byte order mark)」:通称BOM(ボム)コードの3文字が先頭に追加されるためです。

UTF-8+BOM付きの3文字は次のコードになります。

BOMコード 文字
0xEF
0xBB
0xBF ソ

先程のシフトJISの1バイトコード(半角文字)のエリアマップだと、0xBBは「サ」になるのですが、シフトJISでは0xEFが第8ビット(最上位ビット)に1が立っているため、2文字で一組の文字コードとして扱われ、それが変換できないために�マークとなり、3バイト目は1文字で変換できるために半角カタカナの「ソ」として現れます。

最後に

「プログラマのための文字コード技術入門」の本が2010年だったとは、7年前なのに未だに文字コードに悩まされるんですね。

HTML Standard 日本語訳によるとEncoding標準は、UTF-8文字エンコーディングの使用を要求することになったし、JSON仕様でもUTF-8エンコード必須になるとのことですが、それでもあと5年くらいは解消されないのかな。
全てがUTF-8で統一されればBOMコードすら不要になるんですけどね。