csvを行ごとに処理する(GO言語)
下のコードをインポートして、
使う時は、上で定義したcsvrowdeal型の匿名関数を
引数に渡して実行するとよい。
下の赤字の部分が実際にパースされる部分
//!!!ここに実際パースされる部分が描かれる。渡される匿名関数が行ごとの処理
この関数はこれから作成するcsv操作ようのライブラリにも使う。
package csvparserow
import (
"encoding/csv"
"fmt"
"io"
"os"
)
//iにforのループ数,cnumに列数
type Csvrowdeal func(row []string, icnt int, cnum int)
//戻り値には最後まで読んだ行数が入る。
func Csvparse(rowF Csvrowdeal, csvr io.Reader, dedelimiter rune) (int, int) {
var err error
//ひとつの行のカラムの長さも考える必要があるかも。
var row []string
//csvのデリ見たが指定できていないのであとでしてい。
//csvを読み込むために必要
cin := csv.NewReader(csvr)
//CSV.Commaもデリミタは1バイトで決め打ちしている。ためこれでよい。
//string[0]で勝手にbyteにキャストされるので後で変換する必要がある。
//runeで入れる必要がある。runeもstringもバイト列のためこのようなことができる。
cin.Comma = dedelimiter
//forの三項目目はfor文の最初に評価されるのでここでも一度読んでおく。
row, err = cin.Read()
i := 0
var cnum int
//ストリームの最後まで読んだら、ENDになる。
for ; err != io.EOF; row, err = cin.Read() {
if i == 0 {
cnum = len(row)
}
//EOF意外のエラーだった場合は標準エラー出力に吐き出す。
if err != io.EOF && err != nil {
fmt.Fprintln(os.Stderr, "CSV形式のデータを正しく読み取れませんでした。")
os.Exit(1)
}
//行ごとの処理を呼び出す関数側で設定する。
//下の呼び出す側の関数
rowF(row, i, cnum)
i++
}
return i, cnum
}
使う時は、上で定義したcsvrowdeal型の匿名関数を
引数に渡して実行するとよい。
下の赤字の部分が実際にパースされる部分
package main //cut -f -d
import (
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"sort"
"strconv"
"strings"
"github.com/KatsutoshiOtogawa/csvparserow"
)
var (
cformat = flag.String("f", "", "help message for f option")
dedelimiter = flag.String("d", ",", "help message for d option")
)
//前から何列削除というふうにも作るべき。fflag
//""で文字列をちゃんと区切らないとエラーになる。
func main() {
//これがないとオプション引数が展開されないので注意。
flag.Parse()
if (*cformat) == "" {
fmt.Fprintln(os.Stderr, "-fオプションは必須です。")
//golangはioutil.Discardを使って捨てることになる。
io.Copy(ioutil.Discard, os.Stdin)
os.Exit(1)
}
var err error
cnum := strings.Split((*cformat), ",")
var col []int
var cols []string
col = make([]int, len(cnum))
cols = make([]string, len(cnum))
icnt := 0
var val int
//ループを使って文字列の数字をintの数字に変更して代入し直している。
for range cnum {
val, err = strconv.Atoi(cnum[icnt])
if err != nil && val > 0 {
fmt.Fprintln(os.Stderr, "-fオプションには自然数を洗濯してください。")
//golangはioutil.Discardを使って捨てることになる。
io.Copy(ioutil.Discard, os.Stdin)
os.Exit(1)
}
//csvの列は0から始まるので一つずれる。
col[icnt] = val - 1
icnt++
}
//Unixコマンドのcut -f 1,3などの指定も順不同のため
//動作を統一させるためにソートを使う。
sort.Ints(col)
//csvをパースするのに使う区切り文字です。
de := rune((*dedelimiter)[0])
//csvをパースした後にもう一度csvに戻すときの区切り文字が入ります。
en := de
_, _ = csvparserow.Csvparse(func(row []string, i int, columnnum int) {
//ループを使ってコマンドから、指定した数字からカラムを指定している。
for j := 0; j < len(cnum); j++ {
cols[j] = row[col[j]]
}
fmt.Println(strings.Join(cols, string(en)))
}, os.Stdin, de)
}
コメント
コメントを投稿