2011/04/17

バッファを1行ずつ処理するマクロ



まあ、置換とかは replace-buffer とかで一発なんだが、もちょっと凝ったことをしたいときがある。


今まではバッファを1行づつ処理するときは、



(while (null (eobp))
(let* ((beg (save-excursion (goto-bol) (point)))
(end (save-excursion (goto-eol) (point)))
(s (buffer-substring beg end)))
(dbg-msgbox s) ; やりたい処理
(forward-line)))


とかやっていた。


すごく冗長に感じていたし、カーソルを動かしたりするのがやるせなかった。行頭と行末のポイントが欲しいだけなのに、save-excursion するのとか、不必要に let* 使うのもちょっと変だと思っていた。まあ、いろいろキモかった。


もうちょっと読みやすいのを考えてみた。今回はマクロで。



;;; バッファを1行ずつ処理する
;;; e.g. (loop-at-buffer (line)
;;; (dbg-msgbox line))
(defmacro loop-at-buffer ((var &optional buffer) &body body)
(let ((gbuf (gensym))
(gstream (gensym)))
`(let* ((,gbuf (cond ((null ,buffer) (selected-buffer))
((bufferp ,buffer) ,buffer)
(t (find-buffer ,buffer))))
(,gstream (if ,gbuf (make-buffer-stream ,gbuf)
(error "\"~A\"という名前のバッファが見つかりません" ,buffer))))
(loop
(let ((,var (read-line ,gstream nil)))
(unless ,var (return nil))
,@body)))))


これを使うと、上の例は↓こう書けるようになる。



(loop-at-buffer (line)
(dbg-msgbox line))


わりといい感じになった。


パラメータは下記の2つ。




  • 第1パラメータは、バッファの1行を取り出した文字列を入れる変数を指定する。省略不可。

  • 第2パラメータは、回すバッファを指定する。省略時は現在のバッファになる。


ちなみに、マクロ内で使ってる make-buffer-stream は xyzzy の関数なんだが、引数に nil を渡すと適当になんかのバッファ(selected-buffer か?)に紐づいたストリームを返すみたいで、具合が悪い。その対策を入れてある。


・・・とここまでやっておいて、実は with-input-from-buffer があったことに気づく。


また車輪やってしまった。





Related Posts Plugin for WordPress, Blogger...

0 コメント :

コメントを投稿