現在、今まで僕が取り扱ったことのないPythonという言語を使ってあるプログラムを組もうと企てています。
レンタルサーバーに環境を構築して・・・というのを考えていたのですが、その環境構築もまた面倒そう(というか僕がよく分かっていない)なので、とりあえずWindows上にApacheとPythonを入れてまずはそこで動くものを作ってしまおうと考えています。サーバー上にデプロイするのはまた後日という事で。
不可解な文字化けが発生した
現在では文字コードはUTF-8を使うのが一般的らしいので、僕もソースからデータベースから全部UTF-8に統一して開発を行う事にしました。
とりあえずWeb画面上から入力した文字や数字などをデータベースに突っ込むという簡単なサンプルを作ってみました。こんなやつです。Webフレームワークも何も使っていません(これもまだよく理解できていないのでw)。
#! C:\Program Files (x86)\Python36-32\python # coding: utf-8 print ('Content-type: text/html\n') print () import pymysql, cgi form = cgi.FieldStorage() #Setup the HTML Page with name of call as title print ('<html>') print ('<head>') print ('<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">') print ('<title>INSERT SAMPLE</title>') print ('</head>') print ('<body>') print ('<form action="/cgi-bin/dbsample3.py" method="POST">') print ('<br>') print ('名前: <input type="text" size="30" name="namae">') print ('年齢: <input type="text" size="30" name="age">') print ('<input type="submit" value="submit" name="button">') namae = form.getvalue('namae', '') toshi = form.getvalue('age', '') sql = 'INSERT INTO 名簿 VALUES(%s, %s)' connection = pymysql.connect( host='localhost', user='xxxx', passwd='xxxx', db='xxxx', charset='utf8') cursor = connection.cursor() try: cursor.execute(sql, (namae, int(toshi))) connection.commit() except pymysql.Error as e: print('pymysql.Error: ', e) connection.close() print ('</form>') print ("</body>") print ("</html>")
するってーと、以下の現象が発生しました。
・ブラウザ上に表示される日本語は文字化けしている
・データベースに入った日本語は正しく表示される
じゃあ13行目の文字コードの指定(ブラウザに文字コードをお知らせする部分)をShift-JISにしたらどうなったかと言うと、次のようになりました。
・ブラウザ上は日本語が正しく表示される
・データベースに入った日本語は文字化けしている
僕はプログラミングは得意ではないので、もうわけが分からない状態に陥りました。
困ったときのGoogle先生
こういう場合は、Googleを検索するとまず間違いなく解決方法を見つけることができます。という事で僕もGoogleをひたすら検索したところ、3日ぐらい経ってようやく解決できました。
まず、以下のコードを実行してみました。
#! C:\Program Files (x86)\Python36-32\python # coding: utf-8 import sys print ('Content-type: text/html\n') print () print (sys.getdefaultencoding()) print (sys.stdout.encoding)
その結果は、
utf-8 cp932
でした。つまり、デフォルトの文字コードはUTF-8だけど、標準出力(print文での出力)はCP932(Shift-JISみたいなもの)だと。
文字化けの現象を解釈すると、printで出力されたCP932の日本語を、ブラウザではUTF-8だと理解して表示したせいで表示が文字化けしたという事です。でもデフォルトがUTF-8だから、UTF-8で表示しているブラウザから入力した日本語はデータベースに正しく入ったと。(上手い説明ができていないかもしれません)
じゃあこの標準出力での文字コードもUTF-8にすることができれば問題は解決する、というところまで進みました。
標準出力の文字コードを設定する方法
これまたGoogleで検索したところsitecustomize.pyという設定ファイルを弄る方法もあったのですが、僕の環境ではそのファイルが見つからなかったので、ソース上で指定する方法を採用しました。
#! C:\Program Files (x86)\Python36-32\python # coding: utf-8 import sys, io sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8') sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8') print ('Content-type: text/html\n') print () print (sys.getdefaultencoding()) print (sys.stdout.encoding)
5~7行目で、標準入力、標準出力、標準エラー出力の文字コードを全てUTF-8に指定することができます。
この1~7行目をおまじないの如く全てのソースに入れていけば、文字化けに関する問題は恐らく発生しないでしょう。
プログラミングの話まで始まってしまい、いよいよごちゃまぜブログの様相を呈してきました。しかし同じような事でお悩みの方にとって助けになればと思い、このエントリーを作ってみました。