Windows7におけるUTF-8の文字化けの対処法

↓これをやってみようかと思っていたのですが、本日はそれ以前のお話です。
[「Rubyで英語記事に含まれてる英単語を数えて出現数順にソートする」をカッコよく書いてみた - Qiita](https://qiita.com/jnchito/items/20cadad6ccb4f06574ea "「Rubyで英語記事に含まれてる英単語を数えて出現数順にソートする」をカッコよく書いてみた - Qiita")

よっしゃー作るぞーと、試しに`input.txt`をtext変数に入力して、出力。
そしたら出ました、文字化け。

# 文字化けはなぜ起こるのか
GitHubからダウンロードしてきたテキストファイルは当然の如く**UTF-8**形式なんですよね。
そしてWindowsではご存知の通り、**Windows-31J**という素敵な文字コードが採用されているわけです。
コンピュータは二進数のビットを行ったり来たりさせているだけですから、文字コードとはそのビット列の解釈の仕方です。
**その解釈の仕方がそれぞれの文字コードで違うため、読み手の意図しない文字に解釈されてしまって文字化けが起こる**のです。ざっくりすぎますね。



```extract_word.rb
# encoding: utf-8
 
text = File.read("../test/input.txt")
p text.encoding
p text
```

```
#<Encoding:Windows-31J> 
"?ｿInterior design and decorating resource Houzz is the overall best Android ap
p of the year, according to Google, which this evening announced the results of
the first-ever Google Play Awards at its developer conference, Google I/O. While
 in previous years, the company had rounded up large numbers of apps for 窶廝est
　(略)
d, the smart airfare prediction engine Hopper won 窶廝est Standout Startup窶\x9D
 and millennial-focused investing app Robinhood grabbed the win for 窶廝est Use
of Material Design.窶\x9D\n\n"
```
んー、エンコードすらできていない、、、？

#解決編
調べてみると僕の手元にある`input.txt`が勝手に**BOM有りUTF-8ファイル**になっていたらしいのです、、、え、爆弾？？？
>**バイトオーダーマーク** (英: byte order mark) あるいは**バイト順マーク**（バイトじゅんマーク）は通称**BOM**（ボム）といわれる、Unicodeの符号化形式で符号化したテキストの先頭につける数バイトのデータのことである。このデータを元にUnicodeで符号化されていることおよび符号化の種類の判別に使用する。
 
>出典: フリー百科事典『ウィキペディア（Wikipedia）』

**BOMの情報が付加されていたから、それも文字の情報として誤って解釈してしまって文字化けが起きていた**ということですね。
なんと、Windowsのメモ帳やExcelでは頼んでもいないのにご丁寧にBOMを付けてくれるらしいのです！

……おっと、こんな厭味な言い方をしてはいけませんね。Microsoft社に悪気はないんです、たぶん。
ちなみにLinuxやMacではBOMを付けられる心配はありません。いいなー。

解決方法は、`File.read`の第二引数に`'r:BOM|UTF-8'`を追加するだけ。
こうしてBOM有りであることを明記することで、BOMのデータを読み飛ばしてくれるようになるそうです。

```extract_word.rb
# encoding: utf-8
 
text = File.open("../test/input.txt", 'r:BOM|UTF-8').read
p text.encoding
p text
```

```
#<Encoding:UTF-8>
"Interior design and decorating resource Houzz is the overall best Android app o
f the year, according to Google, which this evening announced the results of the
 first-ever Google Play Awards at its developer conference, Google I/O. While in
 previous years, the company had rounded up large numbers of apps for \u201CBest
　(略)
axy of Heroes.\n\nFrom the startup world, the smart airfare prediction engine Ho
pper won \u201CBest Standout Startup\u201D and millennial-focused investing app
Robinhood grabbed the win for \u201CBest Use of Material Design.\u201D\n\n"
```
惜しい！
ところどころにUnicodeの名残があるのですが、お前はどっからきた？？？

まあでもあとは使ってる記号も少ないから、
　**u201C → 0xE2 0x80 0x9C(e2809c)
　u201D → 0xE2 0x80 0x9D(e2809d)
　u2019 → 0xE2 0x80 0x99(e28099)**
に変換しちゃえばいいだけなんですけど。なんか『力技』って感じで嫌じゃないですか。

コマンドプロンプトが怪しい、、、と睨んだらドンピシャっぽかったです。
`$chcp`でコマンドプロンプトの文字コードを確認すると、`932(Shift-JIS)`になっています。
~~Shift-JISはWindows-31Jの親みたいなもので、ここでは同じものと考えてしまいましょう。~~
(追記：scivolaさんからCP 932とWindows-31Jは同じものだとご指摘いただきました！
 そして、Shift-JISとWindows-31Jは厳密に言うと違うものです、申し訳ございませんでした、、、
 詳しくは[こちら](http://una.soragoto.net/topics/13.html "Shift_JIS、CP932、MS932、Windows-31J")をご覧ください)

`$chcp 65001`で`65001(UTF-8)`に変更しましょう。
コマンドプロンプトはまず疑うべきポイントでしたね、うっかりしていました。

```
$chcp
現在のコード ページ: 932
$chcp 65001
--------------------------------------------------------------------------------
$chcp
Active code page: 65001

$ruby extract_word.rb
#<Encoding:UTF-8>
"Interior design and decorating resource Houzz is the overall best Android app o
f the year, according to Google, which this evening announced the results of the
 first-ever Google Play Awards at its developer conference, Google I/O. While in
 previous years, the company had rounded up large numbers of apps for “Best of”
　(略)
e startup world, the smart airfare prediction engine Hopper won “Best Standout S
tartup” and millennial-focused investing app Robinhood grabbed the win for “Best
 Use of Material Design.”\n\n"
```
できたー。
#まとめ
**文字化けが起きたらどこかで文字コードが噛み合っていないということ**なので、どちらかに統一しなくてはなりません。
今回の場合、テキストファイルがそもそもUTF-8で記述されているわけですから、そちらに合わせるのが無難でしょう。
**入力から出力に至るまでの一連の流れに関わる全員で「UTF-8を使うんだぞ！」という合意**が必要です。
「いや！俺はWindows-31Jだ！」という頑固者がひとりでもいるから文字化けが起こるのです。
今回の場合、チェック項目はとりあえず、この3点でしょうか。 

  * **テキストファイル**
  * **rbファイル**
  * **コマンドプロンプト**

そして、WindowsユーザさんはUTF-8のテキストやxls,xlsx,xlsmファイルに付いている**BOM**にご用心。
`File.open("xxx.txt", 'r:BOM|UTF-8')`でBOMを避けて開きましょう。

##でも、ひとつ疑問が、、、
この`'r:BOM|UTF-8'`って、どういう意味なのでしょう。。。
いや、僕のググりがまだ甘いだけなんですけどね。。。
試しに`'r:UTF-8'`でやってみたらどうなるのでしょう、、、？

```extract_word.rb
# encoding: utf-8
 
text = File.open("../test/input.txt", 'r:UTF-8').read
p text.encoding
p text
```

```
(Active code page: 65001)

$ruby extract_word.rb
#<Encoding:UTF-8>

"a?≫i??Interior design and decorating resource Houzz is the overall best Android
 app of the year, according to Google, which this evening announced the results
of the first-ever Google Play Awards at its developer conference, Google I/O. Wh
ile in previous years, the company had rounded up large numbers of apps for ca¶a
　(略)
n\nFrom the startup world, the smart airfare prediction engine Hopper won ca¶a≫?
est Standout Startupca¶a?≫and millennial-focused investing app Robinhood grabbed
 the win for ca¶a≫?est Use of Material Design.ca¶a??n\n"


(現在のコード ページ: 932)

$ruby extract_word.rb
#<Encoding:UTF-8>
"\uFEFFInterior design and decorating resource Houzz is the overall best Android
 app of the year, according to Google, which this evening announced the results
of the first-ever Google Play Awards at its developer conference, Google I/O. Wh
ile in previous years, the company had rounded up large numbers of apps for \u20
　(略)
rs Galaxy of Heroes.\n\nFrom the startup world, the smart airfare prediction eng
ine Hopper won \u201CBest Standout Startup\u201D and millennial-focused investin
g app Robinhood grabbed the win for \u201CBest Use of Material Design.\u201D\n\n
"
```
Windows-31Jだと`'r:BOM|UTF-8'`と結果は変わらないのですが、UTF-8に変更すると見たこともない文字化けが起きてしまっています。

……えーっと、これは一体どういうことなのでしょうか。笑
Qiitaの記事で丸投げ、なんてあっていいものなのか分かりませんが、
分かる方、教えていただけたら嬉しいです！

**(追記：コメントでscivolaさんが解説してくださっています！　本記事の何百倍も有益なのでそちらをご覧ください笑)**

#参考
https://qiita.com/KitaitiMakoto/items/2e2d425e439d4b16a279