Emacs Lisp - call-process, 旧字・旧仮名変換

misima 旧字・旧仮名遣い変換の Tomcat7 開発環境を整備したついでに,misima を 多言語エディタ GNU Emacs 24 (Version 24.3, 2013.3.11) から利用する Emacs Lisp も入れ込んだ。misima は現在では Web アプリケーションとして限定公開するだけだが,私自身はまったくこれを使わず,もっぱら Emacs 上から misima プログラムを呼び出して変換操作をする。

misima Emacs Lisp: misima.el は Emacs の同期プロセス生成機能を使って misima をコールし,misima 出力を Emacs バッファに挿入する。すなわち,call-process-region 関数を使用している。たとえば,選択リージョンのテキストに対し旧字・旧仮名遣い・用語用字指定で変換するための misima-ucs-region 関数の定義部分は以下のとおりである。

(defvar misima-path "/usr/local/bin/misima"
  "Path for programm misima. Default: /usr/local/bin/misima")
(defvar misima-rc "$HOME/.misimarc"
  "Path for misima rcfile. Default: $HOME/.misimarc")
(set-default-coding-systems 'utf-8)
;; リージョンを旧字・旧仮名遣い・用字用語変換し Unicode 文字で出力
(defun misima-ucs-region (start end)
  "Replace UTF-8 characters of specified region by old orthography. (UCS)"
  (interactive "r")
  (call-process-region 
   start end
   misima-path
   t (list t nil) nil  ;; delete(t) destination(list) display(nil)
   "-ykitq" "-s" "c" "-r" ;; misima 変換オプション
   misima-rc)
  )
;; 中略(その他関数の記述)
(provide 'misima)

call-process-region の書式は次のとおりである。

call-process-region start end program &optional delete destination display &rest args
 ここで,
 - start end: リージョンの開始点及び終了点
 - program: コールするプログラム
 - delete*: nil 以外を指定するとリージョンを削除
 - destination*: 出力先 - t: カーソル前挿入; nil: 破棄; 文字列: バッファ
 - display*: nil 以外を指定すると挿入後バッファを再表示
 - &rest args: これ以降はプログラムへ渡す引数
 (* 付加オプションは任意)

misima-ucs-region 関数では destination(list t nil) とリスト指定しており,この場合,標準出力をカーソル前に挿入し(ひとつめの t),標準エラー出力を破棄する(ふたつめの nil)ことを意味する。misima.el を Emacs Lisp パスの通ったところに格納し,.emacs(Emacs の初期設定ファイル)に (require 'misima) と記述してこれを読み込ませると,/usr/local/bin/misima をサブプロセスとして起動し,リージョンのテキストを標準入力として misima に渡して,標準出力から得られる変換結果でリージョンを置換する。つまり,標準入力からデータを読んで処理を行い結果を標準出力に書き出す構造のプログラム ー いわゆるフィルタ ー なら,これと同じようにして Emacs 上で活用することができるわけである。

注意すべきは,プログラムのコマンドライン引数の指定において文字列をダブルクォーテーションで括るのだが空白文字がある場合は個別に空白文字で分けて指定しなければならないこと。つまり,上記例でいえば,通常のコマンドライン引数は "-ykitq -s c -r rcfile" なのだが,call-process-region ではこれはエラーとなり,"-ykitq" "-s" "c" "-r" "rcfile" のように空白部分で分けて記述しなければならない。

Mavericks Emacs-24 で misima.el の設置をした。ところが,M-x misima-ucs-region を実行すると,期待に反しリージョンテキストが消えてしまった。Mac OS のターミナルで直に misima を実行するときちんと変換されるのに。これには,ちょっと悩んだ。Emacs Lisp は call-process-region 以外ほとんど書いていなし,*Message* バッファにエラーも出ていないので,環境の問題を疑った。

上記 Emacs Lisp では misima のエラー出力を破棄しているので,それをファイル出力に変えて(つまり destination(list t "error.txt") に変更して)みると,"chasen: can't open .chasenrc, .jumanrc, or /opt/local/etc/chasen/chasenrc" とのエラーがエラーファイル error.txt に出ていた。つまり,日本語形態素解析ソフト茶筌の初期設定ファイルが見つからない,ということ。Mac の Emacs はシェルで設定した環境変数が読めないわけだと合点。よって,.emacs(require 'misima) 行の前に次の記述を追加して再実行したら,ばっちりだった。

(setenv "CHASENRC" "/opt/local/etc/chasen/chasenrc-ipadic-utf8")

もしくは UTF-8 用の chasenrc$HOME/.chasenrc にコピーするのでもよい。

cp /opt/local/etc/chasen/chasenrc-ipadic-utf8 ~/.chasenrc
20140123-emacs-1.png
変換前: リージョン選択して misima-ucs-region 関数を実行
20140123-emacs-2.png
変換後: リージョンが置換された

Emacs Lisp の解説はインターネットリソース上にもたくさん記事がある。けれども,私は対象をきちんと理解しようとすると冊子体で勉強しないとダメなほうである。以下の Emacs Lisp リファレンスマニュアルは Emacs の作者 Richard Stallman が関わったもっとも信頼できる参考書である。Emacs のバージョンは古びてしまったが,Emacs Lisp 言語そのものはほとんど変わらない。call-process 関連については本書の 699 ページに詳しい解説が掲載されている。

Emacs Lispリファレンスマニュアル
ビル・ルイス,リチャード・M. ストールマン,ダン・ラリベルト
the GNU Manual Group
アスキー