proglog

主にプログラミングに関する断片的メモ

howmの1日1ファイルを切り分ける。

継続がよく分からなくて、しばらくそのままにしておいたschemeを再開。
ファイル処理辺りからが実用的でいいかも。
で、howmの1日1ファイルのメモを切り分けるプログラムを書きながら勉強してみようかと。

やることは単純で、行頭の"="を見たら、新しいファイルを開いて、その行から書き出す、ということの繰り返し。
ファイル名に使う日付とか時間とかはひとまず後回し。
まずは連番のファイル名とする。

使うのはGaucheのversion 0.9 [utf-8] windows版。

対象メモファイルは howm-tutorial.howm

まずは、闇雲に書いてみる。
perlのファイルハンドル的なものがschemeではportらしい。

(define (howmsplit0)
  (define (header? buf)
    (and (number? (string-scan buf "=")) (= 0 (string-scan buf "="))))
  (define (opendfileport? port)
    (and (not (number? (string-scan (port-name port) "std"))) (not (port-closed? port))))
  (with-input-from-file "./howm-tutorial.howm"
    (lambda ()
      (let loop ((buf (read-line)) (file-port (current-output-port)) (filenum 0))
	(cond
	 ((not (eof-object? buf))
	  (cond
	   ((header? buf)
		 (if (opendfileport? file-port) (close-output-port file-port))
		 (set! filenum (+ filenum 1))
		 (set! file-port (open-output-file (number->string filenum)))))
	  (display buf file-port)
	  (newline file-port)
	  (loop (read-line) file-port filenum))
	 (else (close-output-port file-port)))))))


(howmsplit0)

データの一時退避場所としてset!を使ったりとか、関数プログラミングっぽくない。
あと、ポートの開け閉めもなんか繁雑。

次がこれ。

(define (howmsplit)
  (define (read-header? buf)
    (cond ((not (eof-object? buf))
	   (cons (and (number? (string-scan buf "=")) (= 0 (string-scan buf "="))) buf))
	  (else (cons #f (eof-object)))))
  (with-input-from-file "./howm-tutorial.howm"
    (lambda ()
      (let loop ((flag-buf (read-header? (read-line))) (filenum 0))
	(cond ((car flag-buf)
	       (with-output-to-file (number->string filenum) (lambda ()
							       (display (cdr flag-buf))
							       (newline)
							       (let wloop ((flag-buf (read-header? (read-line))))
								 (cond ((car flag-buf)
									(loop flag-buf (+ filenum 1)))
								       ((not (eof-object? (cdr flag-buf)))
									(display (cdr flag-buf))
									(newline)
									(wloop (read-header? (read-line)))))))))
	      (else (loop (read-header? (read-line)) filenum)))))))


(howmsplit)

set!を使った明示的な代入は、名前付きletのループの初期化部中に隠蔽。
portの面倒を見てくれる関数を使う。

が、read-header?という、ヘッダ判定と真偽を、その対象のデータとのpairで返すという関数を使うことに。

もうちょっとなんとかならないのかなあ。