2010年2月7日日曜日

日本語ファイル名を持つファイルを含む zip ファイルを、utf-8 .tar.gz に変換する

 ZIPは古い圧縮形式です。ZIPではアーカイブのファイル名の文字コードは決まっておらず、世界各国でばらばらでした。日本ではZIPアーカイブに含まれるファイル名の文字コードは、ほぼ Shift_JIS(CP932)で統一されています。Windows XP に組み込まれている explorer も、日本では ZIPファイルのファイル名は Shift_JISとして扱います。

しかしながら、Linuxの unzip コマンドは、ZIPに含まれるファイル名を、ヨーロッパ系の文字コードと仮定して、勝手にUTF-8に直して展開します。そのため、多くの日本のZIPファイルはLinuxでは正しく扱うことができません。

これでは後々のトラブルを起こす原因になりかねないので、日本のzipファイルの中に入っている Shift_JISのファイル名を、すべて一括して、UTF-8のファイル名に変換して、tar.gz のアーカイブに変換することにしました。

標準の unzip を使っている限り、日本語を扱うことはできません。まずは、ファイル名の変換を抑制するための改造を行います。そのために、infozip のページ(http://sourceforge.jp/projects/sfnet_infozip/releases/)から、ソースコード "unzip60.tar.gz" をダウンロードします。


% tar xvfz unzip60.tar.gz
 % cd unzip60
 % cp unix/Makefile .


次に、fileio.c の、Ext_ASCII_TO_Native を呼び出している2箇所をコメントアウトします。そして、そのファイルをコンパイルし、インストールします。(デフォルトでは、/usr/local/bin/ にインストールされます。)

% make generic 
 % sudo make install

次に、/tmp ディレクトリに、専用のテンポラリディレクトリを作り(仮に /tmp/arc とします)、次のスクリプトを、パスに通しておきます。

#/bin/sh 
rm -rf /tmp/arc/*
dir=`dirname "$1"`
base=`basename "$1" .zip`
/usr/local/bin/unzip "$1" -d /tmp/arc/
convmv --notest -r -f sjis -t utf-8 /tmp/arc/*
tar cvfz "$dir/$base.tar.gz" --directory=/tmp/arc "."

このスクリプトを使うと、日本語ファイルの .zip ファイルを、コマンド一発で、UTF-8のファイル名を持つ .tar.gz に変換することができます。(ファイル名に空白が含まれる場合は、クォートに注意しましょう)。

2010年2月5日金曜日

Emacs で 青空文庫を読む。

今回は、Lookup に添付されている 青空文庫ビューアを使って、気軽に Emacs で、青空文庫を読む方法を紹介したいと思います。

前準備として、青空文庫の一式をダウンロードします。BitTorrent等で配布されている DVD 版(青空文庫・全)を利用するのが便利です。このDVDの「作家別フォルダ」には、各作品は作者ごとに分類され、ディレクトリ名は「作者名」、ファイル名は「作品名」で日本語ファイル名となっているため、diredで楽にブラウズできます。ただし、ディレクトリ名の末尾の作品数を示すカッコつきの数字は削った方が、DVD発行以降の作品を入れる際には便利です。(ファイル名の一括置換には、diredの新機能である wdired-change-to-wdired-mode を活用するのが便利です。)

「青空文庫・全」には追加となる「青空文庫・差分配信」もあります。ただし差分配信の方は、各作者フォルダ内の各作品フォルダ内に、各ファイルがzipで固められた状態で配布されています。これを一括して解き、かつそれらを日本語ファイル名を持つテキストファイルとして保存するためには、以下のようなコマンドを実行します。

$ for file in */*.zip;
 > unzip -p $file > `dirname $file`/`basename $file .zip`.txt

生成されたファイルを、既存の青空文庫の作家別フォルダにマージするためには、まず
cd 090305_txt
mv * ..<path_to>../作家別フォルダ
として、「青空文庫・全」と重複していない作家の作品を移動し(重複している作家の分はエラーとなりコピーされません)、次に、
for file in */*.txt
 > mv $file ..../作家別フォルダ/`dirname $file`
のようにして、残りの「青空文庫・全」と作家の重複している作品を移動します。

さらに作品の活用を目指すのならば、全てのテキストファイルを iconv(CP932用のパッチを当てた版を用意しておくと便利です)で UTF-8 に変換し、手持ちのパソコンの検索エンジンでインデックスを作っておくと、諺や言い回しからの検索もできるようになり、さらに楽しみ方が広がります。

Emacs 青空文庫ビューアを使うには、まず、M-x load-library aozora-view をしておき、青空文庫のテキストファイル(拡張子は必ず.txtでなければなりません)のバッファで、M-x aozora-view を実行します。すると、新しいバッファが作られ、そこに文字を調整した表示バッファが表示されます。ルビ位置の計算がややかかるので、2回目以降は素早く表示できるよう、キャッシュファイルを保存しておくことができます。



Emacsは縦書きはできません。小説を読む際に、どのフォントが読みやすいのか、様々な漢字とかなを組み合わせて試してみるのが良いでしょう。

これを簡単に行うために、以下のようなスクリプトを作ってみました。これを使うと、漢字・仮名・ローマ字において、様々なフォントや背景色を、キーボードの1キー入力で切り替えることができます。

(defun list-rotate-forward (ring)
  (let ((item (car ring))
        (last (last ring)))
    (setcdr last (list item))
    (cdr ring)))

(defun list-rotate-backward (ring)
  (let ((item (car (last ring)))
        (last2 (last ring 2)))
    (setcdr last2 nil)
    (cons item ring)))

;; color-theme を使う。
(require 'color-theme nil t)

(defvar color-theme-set (cdr (cdr (mapcar 'car color-themes))))

(defvar kana-font-set
  '("ヒラギノ明朝 Pro"
    "ヒラギノ丸ゴ Pro"
    "ヒラギノ角ゴ Pro"
    "PMinIWA-HW-Md" ;; "PMinIWA-Md" ← 非固定幅
    "小塚明朝 Pr6N"
    "小塚ゴシック Pr6N"
    "IPA明朝"
    "IPAゴシック"))

(defvar kanji-font-set
  (append kana-font-set '("Hanazono Mincho OT xProN")))

(defvar font-size-set '(12 16 20 28 40))

(defvar ascii-font-set
  '("Droid Sans Mono"
    "Inconsolata"
    "DejaVu Sans Mono"))

(defvar set-rotate-set
  '((ascii-font-set . "ASCII")
    (kana-font-set . "かな")
    (kanji-font-set . "漢字")
    (font-size-set . "フォントサイズ")
    (color-theme-set . "テーマ")))

(defun rotate-rotate-set-forward ()
  (interactive)
  (setq set-rotate-set (list-rotate-forward set-rotate-set))
  (message "Rotate Set = %s" (cdar set-rotate-set)))

(defun rotate-rotate-set-backward ()
  (interactive)
  (setq set-rotate-set (list-rotate-backward set-rotate-set))
  (message "Rotate Set = %s" (cdar set-rotate-set)))

(defun rotate-set-forward ()
  (interactive)
  (let ((set (caar set-rotate-set))
        (name (cdar set-rotate-set)))
    (set set (list-rotate-forward (eval set)))
    (message "%s=%s" name (car (eval set)))
    (update-current-settings)))

(defun rotate-set-backward ()
  (interactive)
  (let ((set (caar set-rotate-set))
        (name (cdar set-rotate-set)))
    (set set (list-rotate-backward (eval set)))
    (message "%s=%s" name (car (eval set)))
    (update-current-settings)))

(global-set-key "\M-\S-f" 'rotate-rotate-set-forward)
(global-set-key "\M-\S-b" 'rotate-rotate-set-backward)
(global-set-key "\M-\S-n" 'rotate-set-forward)
(global-set-key "\M-\S-p" 'rotate-set-backward)
;
;;; フォント幅テスト用の文字列。|
;;; 1234567890123456789012345678|
;;; 上記の二本の縦棒が揃えば、全角・半角が揃っている。(例:Inconsolata & 小塚・ヒラギノ書体)
(defun update-current-settings ()
  "自分の好みのフォントセットに変更する。"
  (interactive)
  (let ((sz (car font-size-set))
        (ascii (car ascii-font-set))
        (kanji (car kanji-font-set))
        (kana  (car kana-font-set))
        (color-theme (car color-theme-set)))
    (if (functionp color-theme) (funcall color-theme))
    ;; 下記以外のフォントは、自動選択に任せる。
    (set-fontset-font nil '(    #x0 .   #x6ff) (font-spec :size sz :family ascii)) ;; 日本語向き。
    (set-fontset-font nil '( #x1700 .  #x171f) (font-spec :family "Tagalog Stylized"))
    (set-fontset-font nil '( #x1720 .  #x1c4f) (font-spec :family "Code2000"))
    (set-fontset-font nil '( #x1720 .  #x1c4f) (font-spec :family "MPH 2B Damase") nil 'prepend)
    (set-fontset-font nil '( #x2000 .  #x33ff) (font-spec :family "HanaMin"))
    (set-fontset-font nil '( #x2000 .  #x33ff) (font-spec :family kana) nil 'prepend)
    (set-fontset-font nil '( #x3400 .  #x9fff) (font-spec :family kanji) nil 'prepend)
    (set-fontset-font nil '( #xa000 .  #xefff) (font-spec :family "MPH 2B Damase"))
    (set-fontset-font nil '( #xf100 .  #xf6ff) (font-spec :family "EUDC2"))
    (set-fontset-font nil '( #xff00 .  #xfffd) (font-spec :family kanji) nil)
    (set-fontset-font nil '(#x10000 . #x10fff) (font-spec :family "Code2001"))
    (set-fontset-font nil '(#x18000 . #x1ffff) (font-spec :family "Unicode Symbols"))
    (set-fontset-font nil '(#x2a700 . #x2fff0) (font-spec :family "HanaMin"))
    ))

上記のコードを .emacs.el に入れておくと、フォントサイズ/背景色/ASCII文字/漢字/かなを、一発で切り替えることができるようになります。まず、何を切り替えるかを、S-M-f, S-M-b で切り替えます。その後、S-M-n, S-M-b で、それぞれを個別に切り替えます。以下に、漢字/かなフォントを幾つか切り替えた例を示します。どの漢字フォントとひらがなフォントの組み合わせが読みやすいでしょうか?



IVSによる異体字表示機能

青空文庫ビューアは、OpenTypeの IVS 表示機能を用いて、書体を古風な漢字に切り替えることができます。そのためには、M-x aozora-view-use-ivs を実行します。

ただし現状では、IVS機能を使えるフォントは、小塚明朝 Pr6N シリーズなどごく一部のフォントに限られます。早くヒラギノ等の他のOpenTypeフォントでも IVS が使えるようになるといいですね。

以下は、小塚明朝フォントを使って、一部の漢字を古風にさせたものです。どの漢字が変化したかわかりますでしょうか?


さて、フォントを変えるだけではなく、今度は背景色や表示色も色々切り替えてみましょう。
一部のライブラリのフォント表示ルーチンは、アンチエイリアス表示をする際に、背景色と表示色のガンマ値を見ないものがあります。そのため、色を変えると見え方がかなり変わる場合があります。


サイズも色々変えてみると面白いかもしれません。それぞれ、12dot, 16dot, 28dot での表示です。

なお、青空文庫ビューアでは"b"ボタンを押す(aozora-view-bookmark)と「しおり」をはさみ、","ボタンを押す(aozora-view-restore-bookmark)と、「しおり」を元に戻します。この「しおり」情報は、aozora-view-bookmarks変数で保存されるので、複数のセッションでこの「しおり」情報を保持したい場合は、session.el をロード後、以下のような設定を行ってください。

(add-to-list 'session-globals-include 'aozora-view-bookmarks)


2009年10月4日日曜日

Emacs + Lookup で Wikipedia辞書を手軽に持ち歩く

Wikipedia の記事データをノートパソコンに入れ、どこでも気軽に素早く引けるようにしたい、という要望は結構、多いかと思います。ここでは、そんな方法の一つを紹介したいと思います。

Wikipedia の全記事データは、wikipedia.org の 公式サイト から圧縮XMLファイルとして、自由にダウンロードできます。

しかし、これをオフラインで読むために、自分のノートパソコンに Wikipedia サーバを構築する作業は、非常に多くの手間と時間を要します。MySQLサーバへの記事の読み込みだけで4・5日かかる場合 も珍しくありません。また数十Gbyteという膨大なHDDを消費します。これでは頻繁に記事データを更新する気力も失せてしまいます。

Wikipedia を辞書標準フォーマットEPwingに変換するツール等もあります。しかしこれらを使ったとしても、作業には半日ほどの時間かかり、また辞書サイズも4Gbyteを超えてしまい、さらにEPwingは日本独自の仕様であるため、JIS X 0208以外の文字が扱えない等の問題がありました。

ここでは、配布されている圧縮Wikipedia記事データをそのまま、解凍せずに手軽に検索して読む方法を紹介します。基本的なアイデアは記事 "Building a (fast) Wikipedia offline reader" に基づいています。

配布圧縮データをそのまま使う利点は、ディスク消費容量の少なさと、導入の容易さです。容量としては、配布圧縮データ+インデックスで、元ファイルの1.3〜 1.6倍程度(2009年10月時点の日本語版Wikipediaで1.3Gbyte, 英語版で8.5Gbyte)の容量しか必要としません。またセットアップも日本語版Wikipediaで1時間程度、英語版でも半日から1日程度(マシンの性能 に依存します)で完了するため、記事を最新版に更新するのも容易です。

この方式は、配布されている圧縮Wikipedia記事データ(日本語版の場合は jawiki-latest-pages-articles.xml.bz2 で、2009年10月時点でおよそ1Gbyteの容量がある)が、"bzip2" 形式で圧縮されていることを利用します。"bzip2" はブロックソート処理を行う都合上、約1Mbyte単位の独立したブロックの並びで構成されています。圧縮ファイルをブロック単位に分割してハードディス クにおいてしまえば、容量はほとんど変わらずに、Wikipediaの記事に対してランダムアクセスに近いことができます。

bzip2 ファイルを分割には "bzip2recover" を利用します。2009年10月時点の jawiki-latest-pages-articles.xml.bz2 を分割すると、およそ5,000近いファイルが生成されます。この分割ファイル群の総容量は、オリジナルとほぼ変わりません。分割後はオリジナルファイルは消去します。この作業は10数分程度でできます。

次に、分割 され、ランダムアクセスできるようになった Wikipedia の記事データに対して、インデックスを作成します。Wikipedia XML ファイルでは、項目タイトルは <title> .... </title> タグで囲まれています。このタイトルを(日本語版では)形態素解析に基づいて分解すると、検索性が高いインデックスを作ることができます。

この作業を高速に行うためのツールとして、"MeCab"と"Xapian" を使用します。この両者の組み合わせで、日本語版Wikipediaならば1時間程度でインデックスが作成できます。(英語版のWikipediaの場合、空白で単語を区切ってインデックス化する作業はおよそ1日ほどかかりました。)

Wikipediaの記事本文は、XMLファイルのtext タグ中にMediaWiki フォーマットで格納されています。MediaWikiフォーマットの記事を自分のノートパソコンで閲覧するには、ノートパソコンにApache Webサーバと、PHPで書かれたMediaWiki/HTML変換ツールを用意しなくてはなりません(上述のWebサイトはこの方法の説明がありま す)。ただ、この方式は処理が重く、テキストベースでさくさくと気軽に記事を読みたいという場合にはあまり向いていません。

MediaWiki (Wikipedia)もwikiの一種類であるため、その書式を plain text に変換するのは難しくありません。ただし MediaWiki をテキスト化するならば、「表組」と「数式」をどのように扱うかが問題になります。Wikipediaでは(しばしば複雑な)表が多用されるため、この 表示をおろそかにする訳にはいきませんし、また理系のリファレンスとしてWikipediaを使う場合、数式をきちんと表示するのは必須です。

「表組」をプレーンテキストに変換するツールとしては、HTMLのテーブルを奇麗に整形、テキスト化する "w3m"が有名です。Mediawikiの表組は容易にHTMLのテーブルに変換できますので、まずMeidaWikiの表をHTML化し、さらにそのHTMLをw3mに食わせることで、MediaWikiの表はプレーテキストにできます。

数式は基本的にはプレーンテキスト化は無理なので、これだけは画像化せざるを得ません。MediaWikiでは、数式は math タグで囲まれたLaTeX形式(のサブセット)で書かれています。この数式を解釈し、そのまま画像化する手軽なツールとして、MediaWikiのツールの一部である texvc がありますので、数式はこれで画像化し、それをテキストに埋め込むようにします。

以上の作業を、ひとまとめに行い、Emacsのバッファで気軽にWikipediaを引くためのツールを、Emacs 辞書検索ソフトウェア、"lookup" の中に組み込んでみました。Wikipediaをノートパソコンで気軽に持ち運びたい、という人はこのツールを検討してみるのはいかがでしょうか。

ただ、本ツールはまだ作り立てなので、CVSサーバからチェックアウトして試用することしかできません(使い方メモが、ndwikipedia.el ファイルのコメント部分にあります)。

本ツールは、Emacs, MeCab、Xapian、MediaWiki (texvc)、w3m、LaTex、bzip2, ruby などを組み合わせています。元サイトの中の人も言っていましたが、多様なツールを組み合わせれば、このような比較的複雑なシステムも簡単に構築できるの が、オープンソースソフトウェアの一つの魅力なのではないかな、と思います。


(数式のみ画像化して貼付けたサンプル画面)


(W3Mを使って、MediaWikiの表組をテキスト化して表示したサンプル画面)

2008年11月7日金曜日

去る10月に、北アルプスの「下の廊下」を歩いてみた。

この歩道は戦前の日本電力株式会社によって整備されたため、「日電歩道」とも呼ばれている。

日本電力は戦後、GHQにより他の様々な会社と統合されて「関西電力」となったが、未だに名前だけは残っている。

積雪のため、一年のうち10月の一ヶ月しか歩くことができない、幻の歩道だが、紅葉と黒部渓谷の絶壁の織りなす風景は絶景。

ただしこの歩道、「けが人がでない歩道」とも呼ばれている。道を踏み外したら、怪我どころではなく確実に死ぬことから。

日電歩道は「焦熱隧道」(黒部第三ダム)、「黒部の太陽」(黒部第四ダム)にも若干、記述がある。数多くの人がここで命を失っている。

毎年、わずか一ヶ月のためにこの歩道を整備してくれる関西電力に感謝。






2008年7月26日土曜日

変貌著しい清亮寺の周辺






Google Earth で東京の変貌を視ていると楽しいのだが、この箇所はとりわけ苦笑してしまった。
かつて、田んぼの真ん中にあった寺は、今や東西南北を川と鉄道で囲まれてしまっている。

100年4世代の間に、この寺はこの周囲の変化をどのように見ていたんだろうか・・・

2008年7月16日水曜日

新しい文字が生まれる時。


 新しい文字が生まれる瞬間とはこんなものなのだろうか。
 薄田泣菫の「白羊宮」を読んでいるとき、このような表記に出くわした。
「イモリ」は漢語では「蠑螈」と書く。

 おそらく版元は何らかの理由で「螈」を作字せざるを得ないとき、「源」の右側と「虫偏」を組み合わせようとしたのではないか。
 しかし、原の字は左下に払いが伸びるので、左上の「さんずい」の名残が残り、結果として、虫偏に「源」という字が作られてしまった・・・そういう想像をしている。

 この詩集は金尾文淵堂による初版以来、幾つかの叢書に再録されているので、
各々がこの字をどのように取り扱ったのか、追跡してみるのも面白いかも知れない。

2008年7月8日火曜日

ポータブルで高速な.emacs.elの書き方



ネットを巡回していると、「ポータブルな .emacs.el の書き方(意訳)」という記事がありましたが、ここではさらに、「ポータブルでかつ高速起動する.emacs.el」の書き方を紹介したいと思います。
すなわち、.emacs.elで拡張ライブラリを設定するときには、

(require 'ライブラリ名)
(add-hook 'xxxx 'yyyy)
....
(setq xxxx 設定値)
....
という記法で書くことが多いのですが、これを以下のような記法で統一します。

(when (locate-library "ライブラリ名")
(autoload '関数名 "ライブラリ名" "関数の簡単な説明")
(autoload 'xxxx "....")
(add-hook 'xxxx 'yyyy)
....
(eval-after-load 'ライブラリ名
'(progn
(setq xxxx 設定値)
....)))
このように書くことで、以下のメリットがあります。

  • 指定されたライブラリが入っていないEmacs環境でも ".emacs.el" はエラーを起こさない。

  • 指定されたライブラリが入っていても、そのライブラリが必要とされるまで、読み込まれない。

この記法を活用すれば、ライブラリは使用するまで読み込まれないので、滅多に利用しないライブラリも安心して ".emacs.el" に組み込めることができます。なお、interactiveな関数(M-x xxxx で起動するタイプ)については、autoloadの第四引数をtにすることで、たとえライブラリが読み込まれなくても M-x xxxxで実行することができるようになります。
また、ライブラリを読み込む前に設定すべき事柄(フック関数など)は、eval-after-load の後には置かないように注意しましょう。