UNIX風のテキストファイルフィルターを書くのに便利なように Perl には
while( <> ){ print $_ }
という構文がある。これと同じような手軽さで Go でもフィルターを書くためのライブラリ argf を書いてみた。
package main import ( "fmt" "os" "github.com/zetamatta/experimental/argf" ) func main() { r := argf.New() for r.Scan() { fmt.Println(r.Text()) } if err := r.Err(); err != nil { fmt.Fprintln(os.Stderr, err.Error()) } }
- 基本インターフェイスは
bufio.Scanner
に準拠した(=ほぼ同じメソッド構成) len(os.Args) < 2
の時は、標準入力から読み取るが、そうでない時はos.Args[1:]
のファイルを順に読み込んでゆくargf.New()
のインスタンスには、AWK の組み込み変数と同じ名前のメソッドを実装している-
NR()
… 読み込みレコード数(行数) -
Filename()
… 現在読み込んでいるファイルの名前 -
FNR()
… 現在のファイルで読み込んだレコード数(行数)
-
かんたんな grep もどきも書いてみた。
package main import ( "errors" "fmt" "github.com/zetamatta/experimental/argf" "os" "regexp" ) func main1() error { if len(os.Args) < 2 { return errors.New("Usage: grep.exe REGEXP Files...") } rx, err := regexp.Compile(os.Args[1]) if err != nil { return err } r := argf.NewFiles(os.Args[2:]) for r.Scan() { if rx.MatchString(r.Text()) { fmt.Printf("%s(%d): %s\n", r.Filename(), r.FNR(), r.Text()) } } return r.Err() } func main() { if err := main1(); err != nil { fmt.Fprintln(os.Stderr, err.Error()) os.Exit(1) } os.Exit(0) }
argf.New()
は os.Args[1:]
を全て読み込み対象としてしまうが、grep もどきでは os.Args[1]
は検索文字列となるので、読み込み対象から除きたい。そのために argf.NewFiles(args []string)
という、読み込み対象のファイル名を、引数で与えるタイプのコンストラクタも用意した。
今週の zetamatta/experimental は以上です。