Category Archives: Python

私がPython3でUnicodeEncodeErrorなのはどう考えてもデフォルト文字コードが悪い!

python_logo

とまぁわかりにくいタイトルですね。
要は「よーしパパ、Python3でCGIやっちゃうぞー」って意気込んだは良いけど
出力するソースに日本語を含んだ途端に
UnicodeEncodeError: ‘ascii’ codec can’t encode characters
なんて文字列に阻まれたりするんですよーってことです(´・ω・`)
(それ以前のパーミッション設定とか注意は サーバーでPythonを使うときに注意すること を参考に)

このエラーを理解するには、Python2.x系と違って
Unicodeとはなんぞやー?とかbyte列とはなんぞやー?とか色々知る必要があるらしい。
あと、Pythonはデフォルト設定をよく読みに行くらしいという特性も知らないと躓きそうです;
正直、僕みたいな文系プログラマーにはわかりにくかったです(ノд`)+゜。

で、結局注意点は
・Pythonのソースコードは基本的にUTF-8で書こうぜ
・一応2行目に # -*- coding: utf-8 -*- みたいにソースのエンコードを指定しようね
・ファイルやフォームからの入出力の際は、必ずエンコード指定しろよー
・レンタルサーバとかにUPしたら、デフォルトエンコードを参考にしちまうみたいだから
 必要に応じて書き換えようぜー

って感じらしい(・ω・)

調べれば調べるほど訳のわからないことをして遠回りしたけど、
結局はこんな感じでデフォルトエンコーディングを書き換えることで日本語表示できましたー

import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')

ちなみにサーバのデフォルトエンコーディングが何かを調べるには

import sys
print(sys.stdout.encoding) # ANSI_X3.4-1968 等を出力

のようにして調べると良いらしい。

とにかく文字コードだけで分厚い本になるぐらい難しい分野だと言われてることだけは
改めてよーくわかりました!(ノ∀`)
でもPythonプログラムを続けるためには、「わからないなりにでも前に進んでる実感がある!」
っていうのが大事だと思うんだ。それは文系プログラマーの大切なモチベーションだからね!

参考サイト
UnicodeEncodeError: に悩まされない。Python2.x から Python3.x への乗り換え
Dive Into Python 3 – 第4章.文字列

文字列の書式指定を使ってHTMLに変数を埋め込む

python_logo

HTMLの中に変数を入れ込むというCGIで良くやるやつです。
ソースはpython3.3を想定して書いてます。

結論から言えば、str.format() を使うだけです。

例えばPHPとかだと

$hello = 'こんにちは!';
print "<p>$hello</p>";
<p>こんにちは!</p>

となる。

これをPythonでやってみる。

hello = 'こんにちは!'
print('<p>' + hello + '</p>')
<p>こんにちは!</p>

んで、そのうちコメント(ヒアドキュメント)とprintf的な書き方を使ったりし始めてー

title = '挨拶は元気よく'
hello = 'こんにちは!'
print('''
<div>
    <h1>%s</h1>
    <p>%s</p>
</div>
''' % title, hello)
<div>
    <h1>挨拶は元気よく</h1>
    <p>こんにちは!</p>
</div>

とまぁここまでなら特に問題ないと思うけど、この書き方だと

1.変数を表示したい順番に並べなければいけない(% title, hello の部分)
2.埋め込まれた箇所を見てどの変数が入っているかわからない(どこを見ても%sだらけに)
 →何番目の変数か数えなきゃいけない!(>’A`)>

やりたいことは
・変数名でそのまま埋め込んで展開したい
・変数名をキーにした辞書(ディクショナリ)で管理したい

ということで解決策は「str.format() メソッドを使う」こと(・ω・)b
一目瞭然ソースを見てみる

greeting = {
    'goodmorning' : 'おはよう!',
    'hello' : 'こんにちは!',
    'goodevening' : 'こんばんは!'    
}
print('''
<p>
    {goodmorning}<br />
    {hello}<br />
    {goodevening}
</p>
'''.format(**greeting))
<p>
    おはよう!<br />
    こんにちは!<br />
    こんばんは!
</p>

辞書を別ファイルにしてインポートする形にすると
色々管理しやすくて良いですね(*´-`)

PythonでCGIを学ぶ

python_logo

CGIはPerlとかPHPが多いイメージだけど、そこをあえてPythonで覚えてみたい!ヾ(・ω・)ノ
そこで下記サイトを参考にさせてもらいながら、基本的なことをまとめてみる。
Python CGIプログラミング入門
Python 2.7ja1 documentation20.2. cgi — CGI (ゲートウェイインタフェース規格) のサポート

500エラーとか出る人は前回の記事 サーバーでPythonを使うときに注意すること をチェック
してみてください(・ω・)b

HTMLとして表示するときは print で最初にヘッダーを書きだして1行開けるのがお約束。

print "Content-Type: text/html"     # 以降のデータが HTML であることを示す行
print                               # ヘッダ部の終了を示す空行

Pythonの中にHTMLコードを書くときは printステートメントをつける。

## こう書いても良いけど…
print "<TITLE>CGI script output</TITLE>"
print "<H1>This is my first CGI script</H1>"
print "Hello, world!"

## 僕はこう書く方が楽で好き
print """
<TITLE>CGI script output</TITLE>
<H1>This is my first CGI script</H1>
Hello, world!
"""

cgiモジュールをインポートする前に、デバッグ用のおまじないを書いておこう。
エラーが発生した際にブラウザ上に詳細なレポートを出力してくれるぞー。

import cgitb
cgitb.enable()

入力されたフォームデータを取得するには、 FieldStorage クラスを使うのがBEST!(゚∇^d) グッ!!
値を取得するには FieldStorage クラスの getfirst メソッドを使う。

import cgi
fs = cgi.FieldStrage()
txt = fs.getfirst('text', '')

print """
    <article>
        <h2>テキストフィールドに入力された文字を表示</h2>
        <p>入力された文字は、<strong>%s</strong> です。</p>
        <form action="cgi_fieldstorage_txtfld.cgi" method="post">
          <input type="text" name="text" />
          <input type="submit" />
        </form>
    </article>
""" % cgi.escape(txt) ## 特殊文字がある場合はHTML上で表示できるようにする

上記のコードのDEMO

サーバーでPythonを使うときに注意すること

python_logo

ちょっとしたことだけど、初めて使うときには躓くよね(´・ω・`)

・拡張子を.pyから.cgiに変更
・パーミッションを755に設定
・改行コードをWindowsのCR+LFからLinuxのLFに変更
・ヘッダでcharsetを指定しない

調べてみると同様の問題についてRubyでの対処法が書いてあったので、
もしかしたらPythonも同じかなぁと思って試したら大丈夫だった(・ω・)b

ちなみにモジュールファイルは.pyで問題なく利用できます。
その際はファイルのパーミッションを600に設定するなどで、
ソースコードが外部から閲覧できないように設定して下さい。

test.cgi

#!/usr/local/bin/python
# -*- coding: utf-8 -*-
 
print "Content-Type: text/html\n"
print
print "Hello world!"

選択肢メニュー表示のNVLモードとADVモード切り替え

WikiLogo
ver 6.14.1

NVLモードで文中に選択肢を表示させるときは、その前段階で

    $ menu = nvl_menu

のように設定しますが、途中でADVモードに切り替えても選択肢メニューまでは切り替わりません(´・ω・`)
試しに

    ## 間違った例
    $ menu = adv_menu

としてもエラーになってしまいます。

解決策として、選択肢メニューはデフォルトではADVモードなので
以下のようにデフォルト設定を上書きすることで解決しました(・ω・)b

    $ menu = renpy.display_menu

NVLモードとADVモードの切り換えって、window show とかも意味合い変わったりするし
色々注意してないとだね(・ω・)

チャプターごとにゲームを開始できるようにする

WikiLogo
ver 6.14.1

チャプターごとにゲームを開始できるようにする

書いてある通りです(・ω・)以上!

screens.rpy の中にある main_menu のあたりを探してメニュー項目を追加するだけ!

        textbutton _("Start Chapter 2") action Start("chapter2")

action Start の引数にラベル名を入れる。空の場合はゲームの先頭から開始になる。
開発中はショートカット代わりに作っても便利ヾ(・ω・)ノ

キャラクター名を独自ウィンドウで表示

WikiLogo
ver 6.14.1

How do I put the character’s name in its own box? に書いてるけど…英語っていうね(;´д`)
以下、内容を簡単適当良い加減超意訳してみた。

Q: どのようにキャラクター名の独自表示領域を設置できますか?
A: “show_two_window” を使えば可能です。
もしあなたがキャラクターの名前をメインウィンドウの外に表示したいとき、次の式をを加える必要があります。

$ e = Character("Eileen", show_two_window=True)

この名前ウィンドウの配置、背景などを編集するには、次の例のように属性を変更することで可能です。

    style.say_who_window.background = Frame("frame.png", 15, 15) #Background skin
    style.say_who_window.xalign = 0.0
    style.say_who_window.yalign = 1.0
    #style.say_who_window.xpos = 100 #For precise placement
    #style.say_who_window.ypos = 100 #For precise placement
    style.say_who_window.left_padding = 15
    style.say_who_window.top_padding = 15
    style.say_who_window.right_padding = 15
    style.say_who_window.bottom_padding = 15
    style.say_who_window.xminimum = 150
    style.say_who_window.yminimum = 15
    style.say_who_window.xfill = False

とりあえずメインウィンドウの外に表示ができた。
全体のイメージが決まるまではデフォルト設定で使ってみよう(・ω・)

レイヤー上に文字を表示する

WikiLogo
ver 6.14.1

暗い画面の真ん中に、「第一章」と白い文字を浮かべる。
これからゲームが始まるときの区切りや、タイトルの演出などに使います。
割りとありきたりな表現ですが、ユーザーへここが区切りであることを伝えやすい方法ですね。

label start:
    show expression Text(&quot;第一章&quot;, size=36, yalign=0.45, xalign=0.5, drop_shadow=(2, 2)) as text1
    show expression Text(&quot;-人の心を持った人形が人間ならば、花の心を持った人間は花になれるのだろうか-&quot;, size=18, yalign=0.55, xalign=0.5, drop_shadow=(2, 2)) as text2
    with Dissolve(1.5)
    pause(4.0)
    hide text1
    hide text2
    with Dissolve(1.5)

show expression Text という命令を使うと、
キャラクターや背景に被せるようにし上部レイヤーに文字を表示できます。
上記の例だと、中央に上下2列でDissolveをかけて表示しています。

pauseをかけて文字の演出をコントロールしてるんだけど、クリックされると
ぱたっとDissolveとかが途切れちゃう。クリック無効にする方法もあるみたいだけど
なんだか上手く行かなかった。色々難しいです。

ルビをつける

WikiLogo
ver 6.14.1

文章にルビをつけるには、まず options.rpy のスタイル設定を変更する。
チュートリアルゲームから該当箇所をまるまんま流用したので詳しいことはわからないヽ(・ω・)/

    ## Note that these only change the size of some of the text. Other
    ## buttons have their own styles.

    style.default.line_leading = 10 # デフォルトのテキスト行間
    style.button_text.line_leading = 0 # ボタンテキストの行間

    style.ruby_style = Style(style.default)
    style.ruby_style.size = 10 # ルビのフォントサイズ
    style.ruby_style.yoffset = -20 # ルビの縦軸位置

    style.default.ruby_style = style.ruby_style # デフォルトのルビ設定に変更を適用する

んでもって、script.rpy などのラベル内文章に {rb}文章{/rb}{rt}ルビ{/rt} という形式で入力するだけ。

label start:
    "{rb}帝都{/rb}{rt}ていと{/rt}。"
    "かつてそう呼ばれた場所、東京。"

普通はゲーム内にルビを振ることはそう多くないと思うのだけど、
友人から誘われたゲームはルビが盛り沢山!(゚д゚;)
手作業ではとても時間がかかってしまう上にヒューマンエラーの可能性も多くなるので、
ルビを辞書化してしまって自動変換することを考えてみた。

といっても、プログラムのド素人が出来ることはたかが知れてるけどね!(ノ∀`)

NVLモード : ナレーションの設定

WikiLogo
ver 6.14.1

NVLモードで会話以外の文章(ナレーション)をさせるには、Characterで定義するが、
通常のキャラ設定のように定義すると、設定したキャラ名(この例ではn)を何度も書かなければいけない。

define n = Character(None, kind=nvl)

label start:
    n "実直で堅実な父だったが、大きな劣等感を抱えていた。"
    n "それは息子であるところの僕に遺憾なく発揮された。"

ナレーションにはデフォルトで予約されている変数narratorがあるので、
そこにNVLモードの設定をしてあげると楽ができます。

define narrator = Character(None, kind=nvl)

label start:
    "実直で堅実な父だったが、大きな劣等感を抱えていた。"
    "それは息子であるところの僕に遺憾なく発揮された。"

ADVモードに戻りたい時は

    $ narrator = Character(None, kind=adv)

といった命令を設定すると元のADVモードに戻ります。