関連記事
概要
上の関連記事であるとおり、皆さんおなじみのKEN_ALLさんが生まれ変わったので、少し遊んでみました。
KEN_ALLさんは、行数も10万行とかを超えてて、且つ、日本語が含まれているので、ファイル操作を覚えるのに個人的にはちょうど良いと思っています。
試してみる
package main import ( "bufio" "encoding/csv" "fmt" "io" "log" "os" "regexp" ) const ( KEN_ALL = "utf_all.csv" ) var ( appLog = log.New(os.Stderr, "", 0) ) func main() { if len(os.Args) <= 1 { fmt.Fprintln(os.Stderr, "./kenall 検索文字列") os.Exit(-1) } re, err := regexp.Compile(os.Args[1]) if err != nil { panic(err) } if err := run(re); err != nil { panic(err) } } func run(re *regexp.Regexp) error { var ( file *os.File err error ) file, err = os.Open(KEN_ALL) if err != nil { return fmt.Errorf("err: os.Open (%w)", err) } defer file.Close() var ( bufReader = bufio.NewReader(file) csvReader = csv.NewReader(bufReader) recCh = make(chan []string) addrCh = make(chan string) resultCh = make(chan string) errCh = make(chan error, 1) ) go read(csvReader, recCh, errCh) go concat(recCh, addrCh, errCh) go find(re, addrCh, resultCh, errCh) LOOP: for { select { case v, ok := <-resultCh: if !ok { break LOOP } appLog.Println(v) case e := <-errCh: return e } } return nil } func read(in *csv.Reader, out chan<- []string, errCh chan<- error) { defer close(out) for { record, err := in.Read() if err == io.EOF { break } if err != nil { errCh <- fmt.Errorf("err: csv.Read (%w)", err) return } out <- record } } func concat(in <-chan []string, out chan<- string, errCh chan<- error) { defer close(out) for v := range in { out <- fmt.Sprintf("%s%s%s", v[6], v[7], v[8]) } } func find(re *regexp.Regexp, in <-chan string, out chan<- string, errCh chan<- error) { defer close(out) for v := range in { if re.FindString(v) != "" { out <- v } } }
タスクファイルは以下。
# https://taskfile.dev version: '3' tasks: clean: cmds: - rm -f utf_all.csv - go clean download: preconditions: - (! test -f utf_all.csv) cmds: - wget https://www.post.japanpost.jp/zipcode/utf_all.csv - file -i utf_all.csv - wc -l utf_all.csv - ls -lh utf_all.csv | awk '{print $5}' ignore_error: true run: cmds: - go build - ./kenall "^東京.*銀座" - cmd: echo ====================================== silent: true - ./kenall "^[^(東京)].*銀座" run-with-time: cmds: - go build - time ./kenall "^東京.*銀座" - cmd: echo ====================================== silent: true - time ./kenall "^[^(東京)].*銀座"
実行すると以下のようになります。
$ task download task: [download] wget https://www.post.japanpost.jp/zipcode/utf_all.csv --2023-07-16 17:46:56-- https://www.post.japanpost.jp/zipcode/utf_all.csv Resolving www.post.japanpost.jp (www.post.japanpost.jp)... 43.253.212.17 Connecting to www.post.japanpost.jp (www.post.japanpost.jp)|43.253.212.17|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 18305986 (17M) [text/csv] Saving to: ‘utf_all.csv’ utf_all.csv 100%[========================================================>] 17.46M 1.89MB/s in 10s 2023-07-16 17:47:07 (1.70 MB/s) - ‘utf_all.csv’ saved [18305986/18305986] task: [download] file -i utf_all.csv utf_all.csv: text/csv; charset=utf-8 task: [download] wc -l utf_all.csv 124270 utf_all.csv task: [download] ls -lh utf_all.csv | awk '{print $5}' 18M $ task run task: [run] go build task: [run] ./kenall "^東京.*銀座" 東京都中央区銀座 ====================================== task: [run] ./kenall "^[^(東京)].*銀座" 北海道夕張郡長沼町銀座 栃木県鹿沼市銀座 埼玉県熊谷市銀座 埼玉県本庄市銀座 富山県富山市新庄銀座 長野県岡谷市銀座 長野県岡谷市東銀座 長野県飯田市銀座 静岡県静岡市清水区銀座 静岡県熱海市銀座町 静岡県伊東市銀座元町 愛知県半田市銀座本町 愛知県刈谷市銀座 滋賀県彦根市銀座町 山口県周南市銀座 山口県周南市みなみ銀座 徳島県徳島市銀座 福岡県北九州市戸畑区銀座
銀座って名前はあっちこっちにあるんだなーって思ったりしてました。
上のコードは、ついでなのでリポジトリ作ってアップしておきました。よければご参考まで。
参考情報
Goのおすすめ書籍
過去の記事については、以下のページからご参照下さい。
サンプルコードは、以下の場所で公開しています。