2010-06-05

Unicode 文字列の折り返し処理をするスクリプト

追記 アップデートあり

ときどき気が向いては Unicode の仕様書 (UAX) などを読んで遊んだりするんだけど、このたび少し形になったのでご紹介。

作り始めてから公開するまでたぶん三年くらいかかってる。「人生の 0.2 % ルール」によって生まれました。

下のやつはひとつの exe になってるので Python なくてもコマンドラインで動きます。

このスクリプトは、テキストファイルを等幅フォントできれいな見栄えになるように指定された桁数で折り返し整形します。よくあるやつです。が、折り返し処理に Unicode の Line Breaking Algorithm (UAX #14) を実装しています。結合文字やサロゲートペアにも対応しているので、アクセント記号付きアルファベットは当然として、小書きのプ―― U+31F7 (KATAKANA LETTER SMALL HU) U+309A (COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK) ――などが使われるアイヌ語のカタカナ表記や、新しく常用漢字に追加された口偏に「七」の「叱」に似た字形の U+20B9F などが使われた文書でも整形できます(それを表示できるエディタを探すほうがたいへんだけど)。

例:

Japanese:
+-------+-------+-------+-------+-------+-------+---
ある日の事でございます。御釈迦様は極楽の蓮池のふち
を、独りでぶらぶら御歩きになっていらっしゃいました。
池の中に咲いている蓮の花は、みんな玉のようにまっ白
で、そのまん中にある金色の蕊からは、何とも云えない好
い匂が、絶間なくあたりへ溢れて居ります。極楽は丁度朝
なのでございましょう。

English:
+-------+-------+-------+-------+-------+-------+---
Alice was beginning to get very tired of sitting by 
her sister on the bank, and of having nothing to 
do: once or twice she had peeped into the book her 
sister was reading, but it had no pictures or 
conversations in it, 'and what is the use of a 
book,' thought Alice 'without pictures or 
conversation?'

English, justified:
+-------+-------+-------+-------+-------+-------+---
Alice was beginning to get very tired of sitting  by
her sister on  the bank,  and of  having nothing  to
do: once or twice she  had peeped into the book  her
sister was  reading,  but  it  had  no  pictures  or
conversations in  it,  'and what  is  the use  of  a
book,'   thought   Alice   'without   pictures    or
conversation?'

French, justified:
+-------+-------+-------+-------+-------+-------+---
Pendant un  demi-siècle,  les bourgeoises  de  Pont-
l'Évêque  envièrent   à  Mme   Aubain  sa   servante
Félicité.

後半の例のように、justification もできます。

サロゲートペア対応などのため、Python 標準の unicodedata モジュールではなく、自前でおんなじようなライブラリをでっちあげてしまった。Python スクリプト版に同梱されている ucd ディレクトリに入っているモジュールがそれです。が、見ると目が腐る可能性があるので気をつけてください。

さて。この uniwrap.py はもとは等幅フォントを前提にした単なるユーティリティではなく、じつは文字列の幅情報を渡せば任意の論理幅で折り返し処理を行なうことができるクラスが入っているライブラリなのだ。だから GUI のテキスト描画にも使える(実際に wxPython と組み合わせて動いてるよ)。要は、まあ夢があるってことです。ドキュメントとかまだないから、細かくは書けないけど。

最後にコマンドライン・オプションの説明。

Usage: uniwrap.py [オプション] ファイル名

オプション:
  -h, --help            ヘルプの表示
  -e ENCODING, --encoding=ENCODING
                        ファイルのエンコーディング
  -x, --expand-tabs     タブをスペースに展開
  -j, --justify         両端揃え (justification)
  -r, --ruler           結果にルーラーを表示
  -t TAB_WIDTH, --tab-width=TAB_WIDTH
                        タブ幅 <8>
  -l, --legacy          全角・半角があいまいな文字を全角として扱う
  -w WRAP_WIDTH, --wrap-width=WRAP_WIDTH
                        折り返し桁数 <60>
  -c, --char-wrap       単純な折り返し処理

「全角・半角があいまいな文字を全角として扱う」は説明が必要かな。これは、要はキリル文字やギリシャ文字などを全角として扱うか半角として扱うかというオプションです。JIS の日本語文書では全角として扱われてますが、ユニバーサルな用途としては当然アルファベットのように扱う必要がある。デフォルトでは後者の扱いになっているので、日本語ローカルのエンコーディングで使う時はオンにしたほうがいい、と思う。

しかし uniwrap という名称は、Unicode に対応している折り返し処理、という意味で名づけたのだけど、なんか台所用品ぽいね……。

2010-04-16

さむい。

「せっかくだから俺はこの実装を選ぶぜ!!」

Python でイベント指向のプログラミングを実現する」という読みものを書きました。

Python で C# (というか .NET?)のイベント機構を実装するという、たぶん誰もが一度は考えるんだろうなあ、という話です。日本語では、tabesugi.net の新山さんが以前日記で触れてたはず。ググると同じような話題がたくさん見つかります。なのでそれらよりもちょっとだけ話を広げてます。Python のデスクリプタの解説が少なかったのでその紹介も兼ねてます。

イベントの利点の説明を省いたのはいくらなんでもなんだけど、書く気力がなかった…。

2010-04-02

ひみつメモ帳」0.8.6 を公開しました。

追記 ダウンロードのリンクが古いバージョンを指していたままだったので修正しました。(2010年4月3日)

主な変更点は OpenSSL 1.0.0 でコンパイルするなど。猿が書いたとか言われてますが猿未満のあたくしはありがたく使わせていただきますよ……。

じつは wxWidgets を使っているのは Mac OS X 版を作りたいからなのだけど、これがけっこうめんどくさい。いや、コンパイルが通るだけでもありがたいことはありがたい。でもメニュー構成あたりは当然プラットフォームに合わせないといけないし、なんか wxMac の Unicode まわりの扱いで躓いたりもして、前途は暗い。

wxTextCtrl というコントロールは Windows の Edit コントロールに相当するのだけど、これが Mac では Windows でいう Rich Edit コントロール相当のものになっている。なのでそのままだとフォントの大きさや色を変えたりできてしまう。もちろんそんなことされてもプレーンテキストベースのひみつメモ帳で保存することはできない。だからこの挙動は殺さなければならない。これは予想外だったので、じつはすごく困っている。

これならそれぞれのプラットフォームのネイティブのライブラリでメモ帳相当の機能作って OpenSSL とリンクしたほうが楽だったんじゃ……とか思ったり。

2010-03-18

もう3月18日!

Twitter のアカウントを作った

Twitter を使い始めました。

もともとアカウント知ってる人たちや、アカウント作る時に Twitter が Gmail のコンタクトにガサ入れして探しだしてきた人たちにはフォローしたりリクエストを送ったりしてますが、それ以外でやってるという人はフォローするなりなんなりで教えてくださいね。

メカ紫も Twitter

誰が嬉しいのかわかりませんが、あのメカ紫も Twitter 始めました。いちおう一日に一回くらいの頻度で何か書くはずです(最初の頃に連投があるのは動作テストのため)。パラメータ設定間違ってない限り。

メカ紫 on Twitter についての説明。企画っぽいこともやってます。

2010-03-12

よりによってこの時期にと思われるかもしれないけど、ラジオを買った。ラジオ聴くのは久しぶりだ。

更新情報

texttemplate.py r1519 公開。この小さなモジュールは今まで結構地味に使ってきていたのだけど(掲示板もこれを使っています)、いまいちコードに自信がなかった。まあ今も自信があるわけじゃないのだけど、このたび結構がんばってリファクタした。行数も減ったし見通しもよくなったので、今後機能の追加もやりやすくなったと思う。

プログラミング読みもの紹介

なんでリファクタリングをがんばったかというと、最近ユニットテストについてのよい読みものを読んだ影響です。ユニットテストについて、じつは今までどうもぴんとこなかった。いや、役割と効用はわかってたつもりだったんだけど、自分の開発手順にどう組み入れていけばよいのかが難しかった。

テストの本とか適当に買って読んでみたりしたのだけど、「境界が危ないのでそこをテストする」とか書いてあって、「引数に -1, 0, 1, 最大値、最大値-1, 最大値+1 を与えてチェック」みたいなことを奨励していた。それでなんというか「あらゆるケースを網羅しておくことでバグをなくす」という神経症的なプロセスに見えて恐れをなしたりしていた。

数値の計算結果を返すような単純な関数ならそれは必要なんだろうけど、それよりも一段階抽象化を進めたレベルのクラスやモジュールではどうなのか。そこでもそんな強迫的なアプローチが必要なのかと思うと、それこそいくつテストケースを書いてもきりがないじゃないかと憂鬱になってしまう。たとえばテンプレートのコードをパースするとして、そのトークンの組み合わせは膨大な量になる。そのほとんどは無効な組み合わせになるわけだけど、それをパーサやハンドラのテストとして網羅的にやるべきなのだろうか? ところが以下のリンクのひとつに、クラスのテストでは「メソッドではなく振る舞いをテストする」と書いてあって、なるほどと思った。ようは、テストにも粒度の概念が必要だというのがわかっていなかったのだった。

それからスタブやモックについても、なんでそんなものが必要になるのかがいまいちよくわかってなかったのだけど、場合によっては小さなクラスのテストにも使えるものなんだということもわかった。(また逆に、必ずしもないといけないものでもないということもわかった。)テストがクラス間の依存関係をなくすのに役立つというのも今ごろになって発見した。

わかっている人にとっては何を今さらというような話だと思うけど、じつはよくわかってなかったことをここに告白しておきます。以下の記事がとても参考になった。英語が多いけど。載せている順に読むのがおすすめです。

あとはあと一年くらい修行したらきっともう少しテスト書けるようになるだろう。

おまけ

リンク紹介したついでにぜんぜん別件ですが最近見つけたものを追加。たいへんわかりやすい JavaScript 入門スライド。