Lambdaカクテル

Common LISPが好きなWeb屋さんです 自宅サーバやフロントエンドもできます

TSVに色をつけるプログラムをSchemeで練習

Schemeを書きたくなったので,適当な課題がないか考えていたら,ログを見易くできるユーティリティがあればいいと思ったので,カラムごとに色をつけるSchemeスクリプトを作ってみた. TSVというか空白文字で区切られているならどれにでも使える.

コード

処理系はGaucheGaucheは組込みライブラリが充実している.案外高速に実行できるらしいので,バッチとかが書けそう. 知っているうちで最も素直な言語のうちの一つだと思う.

#!/usr/bin/env gosh

(define (color-code-by-idx idx)
  (string-append "\x1b[" (number->string (+ 31 idx)) "m"))
(define (main args)
  (let loop ([c (read-char)] [col 0]) ; 初期値
    (if
     (eof-object? c)
     (begin
       (display (color-code-by-idx 8))
       (exit 0))
     (begin
       (display (color-code-by-idx col))
       (display c)
       (cond
        ((eqv? c #\newline)
         (loop [read-char] 0))
        ((char-whitespace? c)
         (loop [read-char] [remainder (+ col 1) 7]))
        (else (loop [read-char] col)))))))

処理の流れ

処理は,色変更コマンドを作る部分と文字を出力する部分とに分かれている.

コンソールの色を変更するには, \x1b[Nm(Nには30から49が入る)というエスケープシーケンスによるコマンドを出力する必要がある. 色と数字の対応は以下のサイトが詳しい.

www.serendip.ws

ここでは前景色のみ変更するため,31..37を使う.30を使わないのは,対応する前景色が黒だからである. 冒頭のcolor-code-by-idxが色変更コマンドを返す関数だ.

1文字読み取り,EOFなら色を戻して終了する.EOFでなければ,色変更コマンドと読み取った文字を出力する.読み取った文字が(改行/空白文字)だったら色のインデックス(を0に戻す/に1加える).そしてループしなおす.

mainという名前で関数をバインドしておくと,スクリプトとして実行された際にそこから実行される(エントリポイント).

このスクリプトの弱点として,連続する空白文字を結合して扱わないので,スペースが2つ入るとカラムも2つ変わったことになる点がある.まあこれは好みの問題.ダブルクオートも認識しないので,色は変わってしまう.ちょっとこれは改善したほうがよいかも.

感想

最初はポートが全面に出てくるような処理を書いていたが,そこまでしなくてもよいと思って普通のread-chardisplayを使う構成にした. 正規表現もしっかりサポートしているので,perlでできることはgoshでもできそうだ.

ただカッコが多いので,エディタのカラースキームに気配りしないと目がチカチカする.EmacsScheme編集モードであるQuackはZenburnが対応していないので,手動でフェイスカラーを設定した.

あと,displayprintとの違いが気になった.前者は改行しないが,後者は改行する.printlnという記法に慣れている身にはまぎらわしい.