文字化けとたたかう

私が先日はまりにはまった文字化けについてまとめてみました。


文字化けが起こる原因として考えられるのは、主に以下の3点です。

  1. ファイルがUTF-8で保存されていない
  2. MySQLの設定がUTF-8になってない
  3. そのほか
では、一つずつ見ていきましょう。


◆ファイルがUTF-8で保存されていない
まずはファイルがUTF-8で保存されているか確認してみましょう。

$ cd アプリのある場所
$ nkf -g ファイル名

Enterを押すと、文字コードの自動判別の結果を表示してくれます。

Shift-JISコードなら

$ Shift-JIS

UTF-8コードなら

$ UTF-8

など。


ここでShift-JISと表示されたら、以下のコマンドを使って変換しましょう。

$ nkf -w --overwrite ファイル名

引数に指定しているファイルをUTF-8に上書きしてくれます。


元ファイルを残したい場合は「--overwrite」は書かず、

$ nkf -w ファイル名

だけで大丈夫です。


ファイルがUTF-8になったか確認してみましょう。

$ nkf -g ファイル名

Enterを押して、UTF-8と表示されたら成功です。
これがLinux文字コードを変換する方法です。


【使い方】

$ nkf オプション ファイル [>出力ファイル]

【オプション一覧】

-g   :自動判別の結果を表示
-w   :UTF-8コードを出力(BOMなし)
-s   :Shift-JISコードを出力
-e   :EUCコードを出力
-Lu  :unix改行形式(LF)に変換
-Lw  :windows改行形式(CRLF)に変換
-Lm  :macintosh改行形式(CR)に変換
--overwrite   :引数のファイルに直接上書き


複数のファイルをまとめて変換することもできます。

  • 文字コードUTF-8に、改行をunix形式(LF)に変換
  • $ nkf -w -Lu --overwrite *.html

    .htmlでまとめて変換しています。



MySQLの設定がUTF-8になってない
Linux文字コードを変換しても駄目なら、MySQLの設定を疑ってみましょう。

まずはMySQLの設定がどうなってるか確認します。

mysql> status;

Enterを押すと、ずらーっとMySQLの設定が出てきます。

mysql> status;
--------------
mysql  Ver 14.7 Distrib 4.1.20, for redhat-linux-gnu (i386) using readline 4.3

Connection id:          36
Current database:       staff2006
Current user:           maiha@localhost
SSL:                    Not in use
Current pager:          lv
Using outfile:          ''
Using delimiter:        ;
Server version:         4.1.20
Protocol version:       10
Connection:             Localhost via UNIX socket
Server characterset:    latin1
Db     characterset:    latin1
Client characterset:    latin1
Conn.  characterset:    latin1
UNIX socket:            /var/lib/mysql/mysql.sock
Uptime:                 1 hour 4 min 14 sec

Threads: 2  Questions: 54354  Slow queries: 0  Opens: 468  Flush tables: 1  Open tables: 64  Queries per second avg: 14.103
--------------

すると、charactersetとついてる4行がlatin1となっているのが分かります。これをUTF-8に直しましょう。
※charactersetは文字コードの設定という意味です。今はlatin1となっていて、文字コードラテン語に設定されています。

では、文字コード関係の変数の値を見てみましょう。show variables like "char%";と打ち込むと、以下のようになるはず。

mysql> show variables like "char%";
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | latin1                     |
| character_set_connection | latin1                     |
| character_set_database   | latin1                     |
| character_set_results    | latin1                     |
| character_set_server     | latin1                     |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+

変数を見てみると「character_set_system」だけがUTF-8になっています。
「/etc/my.cnf」の設定を変更して他の変数もすべてUTF-8にしましょう。

まず、インストールしたMySQLの中のサンプルをコピーします。

$ cp /usr/local/mysql/support-files/my-medium.cnf /etc/my.cnf

「cp」はコピーを意味します。
このコマンドは、
「/usr/local/mysql/support-files/」という階層にある「my-medium.cnf」というファイルを
「/etc/」という階層の中に「my.cnf」という名前でファイルコピーをしてください、という意味になります。


これを入力後、etcディレクトリに移動します。

$ cd /etc

次に、my.cnfを編集します。

$ vi my.cnf

Enterを押すと

E325: ATTENTION
 ・・・・
-- More --

と表示されるので、Enterを押し続けます。
すると「--More--」の部分が「[O]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (D)elete it:」となるので、キーボードでEを押してください。
ファイルの中身が表示されて、内容を編集できるようになりました。
キーボードの↓キーもしくはjキーでスクロールをして[mysqld]の箇所に行き、

[mysqld]
default-character-set=utf8
skip-character-set-client-handshake

を入力します。
これは1行目でデフォルトの文字コードを指定し、2行目で「余計なことをするな」と命令しています。

続けてescボタンを押し、「:w」コマンドを入力してEnterを押すと、my.cnfが上書き保存されました。
「:q」コマンドを入力してviを終了します。
サーバの設定を変更したので、MySQLを再起動しましょう。
最後にもう一度show variables like "char%";と打ち込んで、変更されたか確認しておきます。

mysql> show variables like "char%";
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+

これでMySQLの設定がUTF-8になりました。



◆そのほか
これでもダメならRails上でファイルの設定をしましょう。
app/controllers/application.rbにbefore_filterを追加します。

class ApplicationController < ActionController::Base
...

  before_filter :set_charset

  private
  def set_charset
    @headers["Content-Type"] = "text/html; charset=UTF-8"
  end

...
end

これでもダメなら!
私の場合はこれでもダメでした。
テストでHTMLの要素の検証を行おうとテストメソッドを書いていたら何度も何度もエラーが出てくるのです。
上記設定を何度試してもダメだったので、最終的に以下のようにコードを書きました。

def test_method
  ...
  ...
  assert @response.body.toutf8.include?("#{@user.name}")
end

裏ワザにはなりますが、エラーは解消されたので結果オーライかなと。




長くなりましたが以上です。
最後までお読みいただきありがとうございます!