Gauche:ファイルの読み書き
ファイルの読み書き
https://gist.github.com/Hamayama/15e4222f6a775fec5c0829361af74e56
- Gauche でテキストファイルを加工するサンプルです。
これは、2つの経路でもらったデータが、片方はタブのインデントで、片方は半角スペースのインデントだったので、半角スペースのインデントに統一するために使ったものです。
データの途中にあるタブは変換しないように、正規表現を使っています。
また、1行ずつ読み込むところには、遅延シーケンスを使っています。
- 以前は、このような用途に Gauche (Scheme) を使うことは、思いつきもしなかったのですが、最近は便利に使えるようになってきました。
機能は最小限で、パラメータは固定で、その都度作成する感じです。
後で忘れて はまらないように、気がついた条件等は先頭のコメントに書いています。
- そういえば、Gauche のユーザリファレンスのポートの項目あたりに、thunk という単語がたくさんでてくるのですが、最初の頃はその意味が分からず、わざわざ thunk のない手続きだけを使ったりしていました。
(あせっているときには「また thunk かよ~」とか言っていました。。。)
(thunk とは、引数なしの手続き (lambda () ...) のことでした。
参考URL : http://d.hatena.ne.jp/higepon/20071202/1196605979 )
hamayama(2017/07/31 22:55:40 UTC)
- Shiro: このパターンだとGaucheRefj:file.filterが使えると思います。
(use file.filter) (define (convert-file infile outfile) (file-filter-for-each (^[line outp] (rxmatch-if (#/^[ \t]*$/ line) (#f) ...処理してoutpに出力...)) :reader read-line :input infile :output outfile))
file.filter
は、定番の「一時ファイルに出力して最後にrename」も同時に サポートします (一時ファイルを使うと、処理中にエラーが発生した場合に 中途半端な出力ファイルを残さないで済む。特に既にある出力ファイルを更新したい場合、 エラー発生時には元のファイルがそのまま残されるので便利)
- hamayama(2017/08/01 12:26:46 UTC): 情報ありがとうございます。また使ってみます。
- hamayama(2017/08/03 12:25:05 UTC): 使ってみて思ったのですが、以下のようなのはどうでしょうか。
;; file-filter-for-each の lambda の出力ポート固定版 (define (file-filter-for-each-to-output proc . args) (apply file-filter-for-each (lambda (data out) (with-output-to-port out (lambda () (proc data)))) args))
例えば、最初のサンプルのケースだと、以下のようになります。(define (convert-file infile outfile) (define space-str (make-string space-size #\space)) (file-filter-for-each-to-output (lambda (line) (rxmatch-if (#/^[ \t]*$/ line) (#f) (print "") (print (regexp-replace-all #/^( *)\t/ line #"\\1~space-str")))) :reader read-line :input infile :output outfile))
すなわち、outfile は指定しながら、lambda の方では出力ポート指定を省略できるというものです。
ユーザーが混乱するかもしれませんが。。。
- hamayama(2018/07/30 12:59:25 UTC): 教えてもらった file.filter の file-filter-for-each の使用例です。
https://gist.github.com/Hamayama/15e4222f6a775fec5c0829361af74e56#file-0201_conv_to_csv-scm
便利でした。