公的機関により公開され、全ての人が自由に使えるできるデータを「オープンデータ」と呼びますが、古くから公開され利用されてきたオープンデータに「郵便番号データ」があります。これは、全国の住所データとしても利用できる貴重なデータです。今回は、Go言語から郵便番号CSVを活用する方法を確認してみましょう。
郵便番号データのダウンロード
日本全国の郵便番号データは、郵便局のWebサイトからダウンロードできます。ZIP形式でこちらからダウンロードできます。
せっかくなので、Go言語でZIPファイルをダウンロードするプログラムを作ってみましょう。 以下のプログラムを「download.go」という名前で保存します。
package main
import (
"io/ioutil"
"net/http"
"os"
"log"
)
func main() {
// URLとファイル名を指定
var url string = "https://www.post.japanpost.jp/zipcode/dl/kogaki/zip/ken_all.zip"
var filename string = "./ken_all.zip"
// Webから取得
res, err := http.Get(url)
if err != nil { log.Fatal(err) }
body, err := ioutil.ReadAll(res.Body)
if err != nil { log.Fatal(err) }
// ファイルへ保存
err = ioutil.WriteFile(filename, body, os.ModePerm)
if err != nil { log.Fatal(err) }
println("ok")
}
そして、コマンドラインで以下のコマンドを実行すると、ZIPファイル「ken_all.zip」をダウンロードします。
go run download.go
http.GetでWebに接続します。そして、io.ReadAllで全てのデータを読み出します。
ZIPファイルを解凍しよう
続いて、ZIPファイルを解凍してみましょう。こちらもGo言語で記述しています。基本的な処理は標準ライブラリに備わっているのがGoの便利なところです。以下のプログラムを「unzip.go」という名前で保存しましょう。
package main
import (
"archive/zip"
"os"
"io"
"log"
)
func main() {
// ファイル名の指定
var filename string = "./ken_all.zip"
// ZIPファイルを開く
unzip, err := zip.OpenReader(filename)
if err != nil { log.Fatal(err) }
defer unzip.Close()
for _, f := range unzip.File {
println("unzip: " + f.Name)
fp, err := f.Open()
if err != nil { log.Fatal(err) }
defer fp.Close()
destFile, err := os.Create(f.Name)
if err != nil { log.Fatal(err) }
io.Copy(destFile, fp)
}
}
以下のコマンドを実行すると、ken_all.zipを解凍し、KEN_ALL.CSVというCSVファイルを取り出します。
go run unzip.go
実行すると次の図のようになります。
解凍処理を行う場合、標準パッケージの「archive/zip」を使います。zip.openReaderでZIPファイルを開いた後、for文でunzip.Fileを繰り返すことで、ファイルを取り出せます。
指定の郵便番号を含む行を表示
さて、いよいよCSVファイルを読みましょう。郵便番号のCSVファイルは、文字エンコーディングがShift_JISとなっています。
そのため、Shift_JISを読み込むライブラリが使えるようにしておきましょう。コマンドラインで以下のコマンドを実行しましょう。
go mod init csvzip
go get golang.org/x/text/encoding/japanese
go get golang.org/x/text/transform
そして、CSVファイルを読み込むプログラムを作りましょう。以下のプログラムを「searchcsv.go」という名前で保存しましょう。
package main
import (
"encoding/csv"
"fmt"
"io"
"os"
"log"
"strings"
"golang.org/x/text/encoding/japanese"
"golang.org/x/text/transform"
)
func main() {
// コマンドライン引数を調べる --- (*1)
if len(os.Args) < 2 {
fmt.Println("searchcsv (zipcode)");
return
}
// 郵便番号を得る --- (*2)
search_zip := strings.Replace(os.Args[1], "-", "", 1)
// CSVファイルを開く --- (*3)
f, err := os.Open("KEN_ALL.CSV")
if err != nil { log.Fatal(err) }
// Shift_JISを読むように指定 --- (*4)
r := csv.NewReader(transform.NewReader(
f, japanese.ShiftJIS.NewDecoder()))
// 一行ずつ読む --- (*5)
for {
row, err := r.Read()
if err == io.EOF { break }
if err != nil { log.Fatal(err) }
zip := row[2] // 郵便番号だけ取り出す --- (*6)
if search_zip == zip {
fmt.Printf("%s が見つかりました!\n", zip)
fmt.Printf("%s%s%s\n", row[6], row[7], row[8])
}
}
}
プログラムを実行するには、以下のようなコマンドを実行します。例えば、105-0011の住所を調べるには、次のように記述します。
go run searchcsv.go 105-0011
コマンドラインで実行すると、次のように、東京都港区芝公園が表示されます。
プログラムを確認してみましょう。(*1)ではコマンドライン引数を取得します。(*2)ではコマンドライン引数の0から数えて1番目の郵便番号を取得します。そして、(*3)で入力CSVのファイルを開きます。(*4)の部分ではShift_JISで読むように指定します。
(*5)ではCSVファイルから一行ずつデータを読み込みます。for文の中、r.Readで一行文読み込みます。そして、(*6)では0から数えて2番目にある郵便番号データを取り出します。そして、検索文字列と郵便番号が合致していれば、住所を表示します。
まとめ
以上、今回は盛りだくさんでしたが、(1)郵便番号データをWebサイトからダウンロードするプログラム、(2)ZIPファイルを解凍するプログラム、(3)CSVファイルから郵便番号を検索するプログラムと、3つのプログラムを作ってみました。いずれも短いプログラムですが、Go言語のプログラムのエッセンスを確認することができるものになりました。
型付きの静的言語でありながら、スクリプト言語のように、手軽に小さなプログラムを組むことができました。「go build ***.go」のコマンドを実行して、実行ファイルにコンパイルすれば、手軽に配布もできます。ちょっとしたプログラムを、ササッと作って、そのまま配布出来るGo言語はやはり良いものです。
自由型プログラマー。くじらはんどにて、プログラミングの楽しさを伝える活動をしている。代表作に、日本語プログラミング言語「なでしこ」 、テキスト音楽「サクラ」など。2001年オンラインソフト大賞入賞、2004年度未踏ユース スーパークリエータ認定、2010年 OSS貢献者章受賞。技術書も多く執筆している。直近では、「シゴトがはかどる Python自動処理の教科書(マイナビ出版)」「すぐに使える!業務で実践できる! PythonによるAI・機械学習・深層学習アプリのつくり方 TensorFlow2対応(ソシム)」「マンガでざっくり学ぶPython(マイナビ出版)」など。