文字化けとたたかう
私が先日はまりにはまった文字化けについてまとめてみました。
文字化けが起こる原因として考えられるのは、主に以下の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 :引数のファイルに直接上書き
複数のファイルをまとめて変換することもできます。
$ nkf -w -Lu --overwrite *.html
.htmlでまとめて変換しています。
$ nkf -s -Lw --overwrite *.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/ | +--------------------------+----------------------------+
◆そのほか
これでもダメなら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
裏ワザにはなりますが、エラーは解消されたので結果オーライかなと。
長くなりましたが以上です。
最後までお読みいただきありがとうございます!