Edited at

Go言語でAWKを作ってみました

More than 1 year has passed since last update.

Go言語の勉強目的で、昔色々とお世話になったAWKの基本機能を作ってみました。

Go言語の特徴としてコンパイルしてコマンド化することができたり、Go言語の豊富なライブラリが使えたりします。

AWKって何?という方のために簡単に説明しますと、入力ファイルや標準入力から1行ずつ文字列を読み込んで、アクションと呼ばれる処理に定義されているパターンにマッチしたらその処理が実行されるような簡易的なプログラミング言語です。簡易的とはいえ上手く使うと様々なテキスト処理が簡単にできます。 AWKは歴史のある言語でサンプルも豊富に見つけることができると思いますので、気になった方はぜひ探してみてください。

以下は簡単なサンプルで、カンマ区切りで数字が並んでいるテキストファイルを読み込んで、最後に合計値を出力するものです。

sample.txt

10,20,30

40,50,60

実行してみます。

$ go run sample.go -i sample.txt

Execute Begin
sample.txt
Execute Action1
Input file is processed one by one per line, then the text is splitted with field separator
"10"
"20"
"30"
Execute Action2
The text 10,20,30 matched with the patten .*20.*
Execute Action1
Input file is processed one by one per line, then the text is splitted with field separator
"40"
"50"
"60"
Execute Action2
Execute End
Sum of the input is 210

こちらはソースコードです。

package main

import (
"fmt"
"github.com/hideshi/goawk"
"regexp"
"strconv"
)

func Begin(app *goawk.App) {
fmt.Println("Execute Begin")
fmt.Println(app.Filename)
}

func Action1(app *goawk.App) {
fmt.Println("Execute Action1")
fmt.Println("Input file is processed one by one per line, then the text is splitted with field separator")
for _, elem := range app.S[1:] {
fmt.Printf("%#v\n", elem)
v, err := strconv.Atoi(elem)
if err != nil {
fmt.Println(err)
} else {
app.VI["sum"] = app.VI["sum"] + v
}
}
}

func Action2(app *goawk.App) {
fmt.Println("Execute Action2")
pattern := ".*20.*"
matched, _ := regexp.MatchString(pattern, app.S[0])
if matched == true {
fmt.Printf("The text %s matched with the patten %s\n", app.S[0], pattern)
}
}

func End(app *goawk.App) {
fmt.Println("Execute End")
fmt.Printf("Sum of the input is %d\n", app.VI["sum"])
}

func main() {
app := new(goawk.App)
actions := []goawk.Action{Begin, Action1, Action2, End}
app.Run(actions)
}