Webページにおける円記号「￥」（→バックスラッシュ）の文字化け問題の解決方法

**(注意) この記事では、円記号をすべて`￥`、バックスラッシュをすべて`＼`と表記していますが、円記号は半角・全角のどちらの場合もあり、バックスラッシュはすべて半角のものとお考えください。**

この記事は、
円記号`￥`が`＼`（バックスラッシュ）に文字化けする現象はよく知られていますが、Webページに関しては、「文字参照」を利用することで解決するのでは？ という仮説に至るまでの話です。（仮説ではありますが、今のところうまくいくのでは？という印象です。）

他のブラウザ・ＯＳでも検証したいのですが、下記の環境だけでもかなり複雑になってしまったので、もし、一般的な環境で、違う結果が出る場合があったら教えてください。

<details><summary>検証環境</summary>
Windows 10 Home (Ver.1909)
Firefox 79.0 (64 ビット)
</details>

# 1. 円記号`￥`が文字化けする原因
下記のようなものが挙げられます。

    * 文字コード
    * フォント
    * エンコード（エンコーディング）

## 1.1. 文字コードが原因の文字化け
円記号`￥`を表す文字コードには、下記のようなものが挙げられます。

    * 5C...半角記号の￥（一部の環境では「＼」(バックスラッシュ)が表示）
    * A5...半角記号の￥（Windowsでは「･」（半角中点）が表示されることも）
    * U+FFE5（ユニコード）、216F（JISコード）...全角記号の￥
    * Webページの文字参照（「&yen;」、「&#xA5;」、「&#165;」）

### 5C
【5C】は、Windowsでは`￥`キー（または`＼`キー）で打ち込まれる文字のコード番号です。

### A5
【A5】は、Windowsでは

>（MS-IMEの場合）
「えん」の変換候補のうち、右側に<strong>[環境依存]</strong>
と表示される候補の文字

のコード番号です。
![MS-IMEにおけるA5コードの選択](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327025/77a2468d-8f6a-3d51-0649-91423c90ab90.jpeg)
Mac環境では、【5C】`＼`、【A5】`￥`とも、それぞれ別々に打ち込めるそうです。

### 全角記号の`￥`
全角記号の`￥`は、

>（MS-IMEの場合）
「えん」の変換候補のうち、右側に<strong>[全]</strong>
と表示される候補の文字

です。
![MSIME_全角.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327025/0f00f45d-70c2-b513-3195-2f91f2fccf07.jpeg)
ユニコードとJISコードではコード番号が異なりますが、コード体系が異なるだけで、実質的には同じ文字を表示するらしいです。

### Webページの文字参照
「&amp;yen;」　「&amp;#xA5;」　「&amp;#165;」
これらは、Webページにおいて、「文字参照」と呼ばれる仕組みで`￥`が表示されるようです。3種類ありますが、実質的にはどれも同じような気がします。（どう違うのか、私にはわかりません。）

ちなみに、「&amp;#x5C;」はフォントによって、`￥`が表示されたり`＼`が表示されたりするようです。

## 1.2. フォントが原因の文字化け
「フォント」とは、各種の文字コードをどのように表示するか（どのようなドットで表現するか）をまとめたファイルです。フォントには、たくさんの種類が存在し、どのフォントが利用できるか、そのうちのどれを優先的に使用するかはケースバイケースです。Webページの場合は、CSSで指定したり、ブラウザがそれを上書きする場合があります。

Webページを見たユーザーが、どのフォントを利用することができるかは、ユーザーの環境によって異なります。現在は、Windows、Mac OS、Android、iPhone（iOS）、iPad（iPadOS） のそれぞれの環境（標準状態でインストールされているフォント）を想定したWebページ作りが必要でしょう。

フォントによっては、収録していない文字コードが存在し、【5C】コードを`￥`と表示するか、それとも`＼`（バックスラッシュ）と表示するか、【A5】コードを収録するか、それとも収録しないか、などは、フォントの製作者に任されています。

また、ほとんどの「欧文フォント」では、日本語を扱いません。そのため、「全角記号」の`￥`は日本語特有の文字なので、収録されていない場合が多いです。

しかし、Webページの場合は、ブラウザが気を利かせて、表示できないはずの文字を、ブラウザの既定フォントで代替表示する場合があります。


## 1.3. エンコードが原因の文字化け
<details open><summary>「エンコード」（エンコーディング）とは、</summary><div>

:::note info

各種の文字コード体系を、さらにコード化するものです。なぜそのようなことをするのかというと、文字と文字の区切りをはっきりさせるためです。

例えば、ユニコードの文字コード体系でいうと、
半角数字の「0」という文字は【30】というコード、
半角英大文字の「B」という文字は、【42】というコード
で表されます。そして、
日本語の「あ」という平仮名は、【3042】というコード
になります。

     【30】  ...半角数字の「0」
     【42】  ...半角英大文字の「B」
     【3042】...平仮名の「あ」

そうすると、【3042】という文字コードがあった場合、どこが文字の区切りか、コンピュータが判断できないため、それが「0B」なのか、それとも「あ」なのか、区別できません。そういうのをはっきりさせるための「決まり」が、「エンコード」（エンコーディング）というわけです。以下、単に「エンコード」と表記します。

エンコードの方式には、ユニコード・JISコードともに、何種類もあります。

日本語Webページの場合は、

    + UTF-8     （ユニコード体系）
    + Shift_JIS （JISコード体系）
    + EUC-JP    （JISコード体系）

のほぼ3種類だけですが、
Windows の「メモ帳」アプリの場合は、

    + UTF-8 （既定）
    + ANSI  （Shift_JIS とほとんど同じ。Windows 10 (Ver.1808) までの既定）

その他のエンコードで保存することができます。
:::
</div></details>

Webページで、エンコードが原因の文字化けを防ぐには、

    * レスポンスヘッダーの指定エンコード
    * HTMLファイル（Webページの本体）の作成・保存エンコード
    * HTMLファイルのmeta要素の指定エンコード

これら３つが一致していることが極めて重要です。
特に上から２つが重要です。

### 1.3.1. レスポンスヘッダーのエンコード指定

Webサーバーは、レスポンスヘッダーを送信して、ブラウザからリクエストがあったページのエンコードを、伝えてくれます。ブラウザは、その指定されたエンコードで、Webページを解釈して画面に表示します。

ところが、Webサイト製作者が、うっかりその指定を忘れるか、あるいはデフォルト（既定）のエンコード（または指定したエンコード）と異なるエンコードでWebページを製作してしまうと、誤った（デフォルトの）レスポンスヘッダーを信じたブラウザが、文字化けを起こしてしまいます。

解決策は、**正しいレスポンスヘッダーを送信する**です。
下記に、PHPを利用したヘッダー送信の一例を挙げておきます。

    header("Content-type: text/html; charset=EUC-JP");

レスポンスヘッダーは、Webページのmeta要素の指定より優先です。
なお、レスポンスヘッダーは、レスポンスbodyが送信される前に送信しなければなりません。**ほんの一文字でもレスポンスbodyが送信された後では無効**です。

ファイルの先頭に**見えないBOM**が存在していて、それがレスポンスbodyとして送信されてしまい、直後にレスポンスヘッダーを送信しようとしてもダメ.....という例があったそうです。

### 1.3.2. HTMLファイル（Webページの本体）の作成・保存エンコード

さて、Webサーバーが送信したレスポンスヘッダーに続いて、Webサーバーは「レスポンスbody」を送信します。これがWebページの本体です。

このWebページは、ページ製作者がWebサーバーの適切なディレクトリに保存（通常は、ページ製作者のローカルコンピュータで製作してから、サーバーへアップロード）するのですが、このページを作成・保存するときに、レスポンスヘッダーで指定したエンコードとは異なるエンコードで作成・保存してしまうと、この文字化けが起こります。

解決策は、**レスポンスヘッダーと同じエンコードでWebページを作成・保存する**です。

Webページや、その元となるファイルを作成・保存するときには、**必ず、エンコードを確認してから保存することが重要**です。

#### エンコードによっては、保存できない文字がある

Windows では、【A5】コードの文字をうまく保存できない場合があります。
「メモ帳」アプリの場合、【A5】コードの文字を表示するには、

>（MS-IMEの場合）
「えん」の変換候補のうち、右側に[環境依存]
と表示される候補の文字を選択

します。

すると、画面に`￥`が表示されたりしますが、この文字が含まれる文書をJISコード体系のエンコード（ANSI）で保存しようとすると、

> このファイルはANSIテキストファイルとして保存すると失われてしまうUnicode形式の文字を含んでいます。.....

![A5保存時のエラー画像](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327025/47354437-25b4-bd9f-e470-95fe832baee0.jpeg)
などとエラー表示が出て、うまく保存することができません。
このエラーの原因がわからないまま、強引に保存を強行してしまうと、
【A5】コードの文字のはずが、【5C】コードに変換されてしまいます。

この時点で、すでに文字化けが発生したと言うことができます。
このように、Windows では、【A5】コードの文字を正しく保存できないことがあります。そのため、Windows で そのような Webページを作成するときには、「UTF-8」エンコードで保存する必要がありそうです。

また、「サクラエディタ（Ver.2.4.1）」というテキストエディタで、【A5】コードを「EUC-JP」エンコードで保存しようとしたときも同様のエラー表示が出ました。強引に保存を試みたところ、【3F】コード（？クエスチョンマーク）に変換されてしまいました。しかし、「UTF-8」エンコードでなら、【A5】コードを保存することはできました。

なお、Windows 10 付属の「メモ帳」アプリでは、「EUC-JP」エンコードでファイルを作成・保存することができないようです。Webページを製作する場合には、目指すエンコードが使えるテキストエディタを使用するようにしましょう。

#### Webページの製作者がエンコードを勘違い
当然のことながら、レスポンスbodyとして送信されるWebページの本体は、レスポンスヘッダーで指定するエンコードと一致していなければ文字化けします。レスポンスヘッダーでは"EUC-JP"が指定されることになっているのに、WebページとなるHTMLファイルをうっかり"UTF-8"で作成・保存すると文字化けしてしまいます。

こういうのは、連絡ミスによっても起こり得ます。サイト管理者が「EUC-JPでサイトを作る」と決めているのに、ページ製作者が違うエンコードでページを作ってしまった場合などです。

Webページ全体が文字化けしている場合は、ほぼ全て、このエンコードの指定ミスが原因でしょう。

### 1.3.3. HTMLファイルのmeta要素のエンコード指定
一例を挙げると、

    <mata charset="UTF-8">

のようなものです。（HTML5の場合）
レスポンスヘッダーでエンコードが指定されない場合に、ここでの指定がWebページのエンコードとして認識されるようです。


# 2. Webページで円記号`￥`が文字化けする原因
1. で見てきた通り、円記号`￥`が文字化けする原因には、

    * 文字コード
    * フォント
    * エンコード（エンコーディング）

の3種類がありました。
Webページでは、これらのいずれもが原因となりうるため、問題をややこしくしています。
そこで、解決のヒントを探すため、
**どのフォントで、どのエンコードで、どの文字コードがどう表示されるか**
調べてみることにしました。

## 2.1. 結果
以下の表中、
「全角」とあるのは全角`￥`がどう表示されたか、
「5C」とあるのは、【5C】コードがどう表示されたか、
「A5」とあるのは、【A5】コードがどう表示されたか、
「&amp;○○○;」とあるのは、文字参照（&amp;○○○;）がどう表示されたか、
を表します。
![UTF-8の調査結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327025/ef71297e-5488-b256-09df-b9a12f86533d.jpeg)

Shift_JISエンコードでは、【A5】コードをファイルに保存できなかったので、代わりに文字参照（&amp;#xA5;）の表示を調査しました。
![Shift_JISの調査結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327025/95ac240f-8fc7-85b0-3a8c-17574f611ecd.jpeg)

EUC-JPエンコードでも、【A5】コードをファイルに保存できなかったので、代わりに文字参照（&amp;#xA5;）の表示を調査しました。
![EUC-JPの調査結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327025/c9f48cbd-cbfa-c8fa-929e-94a0f23d1422.jpeg)

これらの結果を見ると、「文字参照（&amp;yen;）」の表示は安定して必ず「円記号」となっています。

ということは、**Webページ上で`￥`記号を必ず表示させたい場合は、
「文字参照（&amp;yen;）」を使えばいいのでは**、という仮説に至ったというわけです。

しかし、残念ながら、これが本当に正しいかどうかは確定しません。
すべてのフォントで必ず`￥`記号が表示されるかどうかを確認するのは、事実上不可能です。

もし、このページを見ている皆さんの中で、「一般的な環境で表示されなかった」という事実があれば、どんな環境かお教えいただきたいと思います。

一方、「文字参照（&amp;#x5C;）」の表示は【5C】コードと変わらない結果でした。これにより、今のところ、**Webページ上で「（半角）バックスラッシュ」を必ず表示させる方法は、その文字に欧文フォントを指定するなど、とても面倒な方法しかない**ということになります。日本語フォントだからとはいっても、「文字参照（&amp;#x5C;）」の表示が`￥`記号というのはなんだかなーという感じです。

とはいえ、Webページ上で「（半角）バックスラッシュ」を必ず表示させなければならないことはあまり無いかな.....