ハングアップの日々

2011年 12月分

2011/12/28

memo

2011/12/27

memo

2011/12/26

HTML, ruby

 Firefox は、HTML の ruby 要素に対応していない。何か方法は無いのかと少しだけ調べてみた。

2011/12/24

Python 2, 3 共用スクリプト

 Python 2.6 以降と Python 3 で共用できるスクリプトが、意外と簡単に書けることもあると知っていろいろ試している。

 まずは、次の 1行を書いておくことが重要。

from __future__ import print_function, unicode_literals, division

これで、Python 2 と Python 3 の間の文法上の非互換点を(ほぼ)解消できる。しかし、文法エラーがなくなっても動作上の非互換点が解消できるわけではない。特に影響が大きいのは文字列の扱いで、Python 3 では、str 型と bytes 型は暗黙的に変換されなくなったため、適宜 str.encode() や bytes.decode() などを使って明示的に変換する必要がある。もっとも、実際に Python 3 上で実行すれば変換が必要な場所はエラーとなるので、修正はそれほど難しくはない。

 今回はまったのは、標準出力、標準エラー出力の文字コードを設定する方法だった。Python 2 では以下のようにして文字コードを設定する方法が一般的のようだ。

    import codecs
    outenc = 'UTF-8'
    sys.stdout = codecs.getwriter(outenc)(sys.stdout)
    sys.stderr = codecs.getwriter(outenc)(sys.stderr)

 Python 3 で使える方法を探したところ、いくつかのサイトで以下のような方法が載っていた。

    outenc = 'UTF-8'
    if sys.version_info[0] < 3:
        # Python 2.x
        import codecs
        sys.stdout = codecs.getwriter(outenc)(sys.stdout)
        sys.stderr = codecs.getwriter(outenc)(sys.stderr)
    else:
        # Python 3.x
        import io
        sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding=outenc)
        sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding=outenc)

しかし、バージョンを見て処理を分けるのはあまり美しくない。さらにリファレンスを確認したところ、TextIOBase.buffer は、TextIOBase API の一部ではないとのこと。
 何か良い方法はないかと思い、次のコードを試してみた。

    import io
    outenc = 'UTF-8'
    sys.stdout = io.open(sys.stdout.fileno(), 'w', encoding=outenc, closefd=False)
    sys.stderr = io.open(sys.stderr.fileno(), 'w', encoding=outenc, closefd=False)

一見、Python 2 でも Python 3 でも同じコードで同じように動作するかに見えたのだが、Python 2 で print() として空行を出力すると、それ以降出力されない問題が発生してしまった。インタラクティブモードで実行してみたところ、以下のようになった。

>>> import sys, io
>>> from __future__ import print_function, unicode_literals
>>> sys.stdout = io.open(sys.stdout.fileno(), 'w', encoding='UTF-8', closefd=False)
>>> print()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: must be unicode, not str

スクリプトで実行していた際には、sys.stdout だけでなく sys.stderr も変更していたために、エラー出力が出ていなかったようだ。print() を実行すると、デフォルト引数の設定により print(end=b'\n') として実行されるのがエラーの原因だった。以下のようにして、print 関数を差し替えて、デフォルト引数 end を Unicode 文字列に設定し直したところ、ようやく Python 2 でも io.open() を使う方法が正常に動くようになった。

org_print = print
def print(*args, **kwargs):
    kw = dict(kwargs)
    kw.setdefault('end', '\n')
    return org_print(*args, **kw)

デフォルト引数 sep も、Python 2 ではバイト型の b' ' がデフォルト値だが、こちらは Unicode 文字列と結合したときに自動的に ' ' に変換されるので、わざわざ Unicode 文字列に設定し直す必要はないと思われる。

 なお、unicode_literals を有効にしても、Python 2 では str は、バイト型のままである。必要に応じて以下のコードを追加すると良いかもしれない。

try:
    str = unicode
except NameError:
    pass

2011/12/19

mintty, マウス制御(続き)

 ローカルの bash プロンプトに戻ったときに、マウスイベントを自動的に無効化できればよいのではないかと思い、調べてみた。
 bash の場合、PROMPT_COMMAND というシェル変数にコマンドをセットしておくと、プロンプト表示前にそのコマンドを実行できるようだ。.bashrc に次のように書き足した。

# stop the mouse events
function stop_mouse {
    echo -ne '\e[?1000l'
}
PROMPT_COMMAND="stop_mouse; $PROMPT_COMMAND"

memo

2011/12/16

mintty, マウス制御

 mintty で ssh を使い、リモートマシンにログインして Vim を使っているときに、ネットワークが切断されたりすると、マウスが有効になったままの状態になってしまう。その状態で画面をクリックしたりすると、変な文字が入力されてしまう。一度ローカルで Vim を立ち上げて終了すれば、マウスは無効化されるが面倒である。
 Xterm Control Sequences に、コントロールシーケンスが載っていた。以下のコマンドを入力することでマウスを無効化することができた。

$ echo -ne '\e[?1000l'

 ESC [ と CSI (0x9b) は同じ制御コードを表すらしい。そういえば地デジの字幕でも CSI という制御コードを使っている。

memo

2011/12/15

Vim, fakeclip

 Cygwin 上の Vim で直接クリップボードを扱えるようにしたいと思い、fakeclip を試してみた。
 ファイルを解凍後、make install でインストールすれば良いようだ。
 インストールしたものの、うまく動いたり動かなかったりして、何かおかしいと思っていたのだが、単にゆっくり入力していたせいでタイムアウトに引っかかっていただけだった。set notimeout ttimeout としておくのが良さそうな感じである。

2011/12/14

Python のサロゲートペアの扱い

 Python でサロゲートペア(BMP 外の文字)の扱いが環境によって異なることに気付いた。

Python 2.6.6 (Ubuntu)

>>> a = u"\U000E0FFF"
>>> a
u'\U000e0fff'
>>> len(a)
1
>>> hex(ord(a))
'0xe0fff'
>>> unichr(0x0010ffff)
u'\U0010ffff'

Python 2.7.2 (Windows)

>>> a = u"\U000E0FFF"
>>> a
u'\U000e0fff'
>>> len(a)
2
>>> hex(ord(a))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: ord() expected a character, but string of length 2 found
>>> unichr(0x0010ffff)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: unichr() arg not in range(0x10000) (narrow Python build)

Python 3.2.2 (Windows)

>>> a = "\U000E0FFF"
>>> len(a)
2
>>> hex(ord(a))
'0xe0fff'
>>> chr(0x0010ffff)
'\U0010ffff'

 wchar_t のビット数が違う(VC++ では wchar_t が 16bit、Linux の GCC では wchar_t が 32bit が一般的)ことに起因するのではないかと想像するが、環境によって動作が異なるのは非常に困る。
 「DSAS開発者の部屋:Python2.x/3.0のunicode内部表現について」によると、Python の configure オプションには --enable-unicode=ucs[24] というものがあり、Ubuntu などでは ucs4 でビルドされているらしい。ひどい話だ。

memo

2011/12/08

MinGW GCC, Cygwin

 ふと、MinGW GCC で msvcrt.dll 以外の msvcr*.dll にリンクできるのだろうかと思い、調べてみた。
 Cygwin にインストールした mingw-gcc 4.5.2 を調べると、

/usr/i686-pc-mingw32/sys-root/mingw/lib/

に、libmsvcrt.a だけでなく、libmsvcr70.a から libmsvcr100.a まで揃っていることに気付いた。問題は、どうやってこれらのファイルにリンクするかだが、"HOWTO Use the GCC specs file | MinGW" に記載があった。specs ファイルというものを用意することで、

i686-pc-mingw32-gcc -specs=msvcr80

などというように -specs オプションでリンクする msvcr*.dll を選択できるようだ。specs ファイルは、

<mingw-root>/lib/gcc/mingw32/<gcc-version>/

に置くようにと記載されているが、Cygwin の mingw-gcc 4.5.2 の場合は、

/lib/gcc/i686-pc-mingw32/4.5.2/

に置けばよさそうである。

 msvcr80.dll と msvcr90.dll の場合は、マニフェストファイルをちゃんと用意しないとダメっぽい?

memo

2011/12/06

memo

2011/12/05

memo

2011/12/03

mp3infp

 mp3infp の非同期化処理が仕様に準拠していないのではないかという話があるらしい。どう解釈するのが正しいのだろうか。

memo


Copyright (C) 2011 K.Takata