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

# はじめに
これは[文字 Advent Calendar 2017](https://qiita.com/advent-calendar/2017/char)の21日目となります。

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

ネットで検索するが、このような現象が無いのか何も見つからなかったが、別の内容で「[「ソ」には特殊な意味がありますか？ - Yahoo!知恵袋](https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1397352803)」で「ソ」による文字化けについて書かれていたのがあり、今回「ソ」繋がりでまとめてみた。

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

何故、「ｿ」なのだろうということで、文字コードを調べてみた。
[シフトJISの1バイトコード（半角文字）のエリアマップ](http://charset.7jp.net/sjis.html)

また、別のアプリケーションではSQLのリテラル文字列の"登録"の文字が逆さまのクエスチョンマーク「¿」になっていた。この[逆疑問符](https://ja.wikipedia.org/wiki/%E9%80%86%E7%96%91%E5%95%8F%E7%AC%A6)はスペイン語で使われるようです。
[Latin-1 アスキーコード表 (ASCII Code Table)](http://charset.7jp.net/ascii.cgi)

|文字|ASCIIコード|2進数|
|:--|:--|:--|
|?|0x3F|00111111|
|ｿ|0xBF|10111111|
|¿|0xBF|10111111|

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

「[プログラマのための文字コード技術入門](http://amzn.to/2kPaxyC)」という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!知恵袋](https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1397352803)

「0x5C問題」と呼ばれるもので、「ソ」以外にも「十」「貼」「能」「表」「暴」「予」などが比較的よく使われる文字としてある。
0x5Cである円マーク(\\)は、多くのプログラミング言語や様々なシステムで制御文字として扱われるようになっており、エスケープシーケンス(escape sequence)と呼ばれています。
例えば正規表現では、(\\d)はすべての半角数字、(\\s)は空白文字といったメタ文字として使われます。円マーク自体を使用したい場合は円マークを2つ記述して回避します。
同様な問題に「ポ」もあり、こちらは7CがASCIIコードでパイプ文字(|)を表すことにより問題が発生する。
どちらも通称や俗称として「ダメ文字」とも呼ばれる。

Shift-JISを使用している場合、ダメ文字を考慮しておかないとプログラムによってはデータを破壊してしまいます。

https://forest.watch.impress.co.jp/docs/serial/yajiuma/1493727.html

* [0x5c問題](http://www5f.biglobe.ne.jp/~fuku-labo/library/program/common/1/004.htm)
* [Shift_JISのダメ文字](https://sites.google.com/site/fudist/Home/grep/sjis-damemoji-jp)
* [ノート:Shift JIS](https://ja.wikipedia.org/wiki/%E3%83%8E%E3%83%BC%E3%83%88%3AShift_JIS)

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

これはUTF-8+BOM付きで保存した際に「[バイトオーダーマーク (byte order mark)](https://ja.wikipedia.org/wiki/%E3%83%90%E3%82%A4%E3%83%88%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%E3%83%9E%E3%83%BC%E3%82%AF)」：通称BOM(ボム)コードの3文字が先頭に追加されるためです。

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

|BOMコード|文字|
|:--|:--|
|0xEF|�|
|0xBB|�|
|0xBF|ｿ|

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

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

[HTML Standard 日本語訳](https://momdo.github.io/html/semantics.html#charset)によるとEncoding標準は、UTF-8文字エンコーディングの使用を要求することになったし、[JSON仕様でもUTF-8エンコード必須](http://www.publickey1.jp/blog/17/jsonrfc_8259ecma-404_2nd_editonutf-8.html)になるとのことですが、それでもあと5年くらいは解消されないのかな。
全てがUTF-8で統一されればBOMコードすら不要になるんですけどね。

Windows 10 19H1からメモ帳のデフォルト保存形式がBOMなしUTF-8になりました。