引っ越しの見積もりフォームで、住所を3つの欄に分けて入れろと言われた。都道府県、市区町村、それ以降。「東京都千代田区内幸町1丁目1-1」を手で分けるのは簡単だけど、これを機械にやらせると話は一気に面倒になる。僕はエージェントに住所を分解させたくて、デジタル庁のアドレス・ベース・レジストリ(ABR)を取りに行った。
起: 国が住所のマスタを無料で出している
ABRは、日本の全住所を正規の階層(都道府県→市区町村→町字)に展開した公式マスタだ。CC BY 4.0で、ユーザー登録なしで機械可読のままダウンロードできる。kurashi-skillの収録条件にすんなり合う。
2026-09-27の実測: 都道府県マスタは47行・2,690バイト。市区町村マスタは1,918行・237,105バイト(郡と政令市の区も入る)。町字マスタは都道府県別で、東京都分は5,940行・1,159,208バイト・38列だった。
承: まず403に阻まれた
データセットのカタログ(ArcGIS Hub)からダウンロードURLを拾ってcurlしたら、CloudFrontの403。User-Agentを変えてもRefererをつけてもだめだった。どうやら出元のネットワークで弾かれるらしい。
困ってカタログのDCAT-USフィード(13,077,529バイト、9,345データセット)を読んだら、同じパス構成のS3ミラー(gov-csv-export-public.s3.ap-northeast-1.amazonaws.com)が公式の配布先として載っていた。こちらはすんなり200。政府のデータは、入口が一つとは限らない。カタログとフィードを読むと迂回路が見つかる。
転: 丁目の数字が、データの中で統一されていない
マスタを読み込んでいざ照合しようとして、本題の罠に出会う。同じ東京都の同じファイルの中で、千代田区の内幸町は「一丁目」(漢数字)なのに、新宿区の歌舞伎町は「1丁目」(全角数字)なのだ。入力側は「1丁目」(半角)と書く。つまり正規化すべき表記ゆれが、正本たるマスタの内部にすら混在している。
救いは chome_number 列で、こちらは常に半角数字の「1」が入る。だから比較はこっちを起点にして、入力の「1丁目」「1丁目」「一丁目」を全部試す。
ほかにも罠はあった。札幌の「北一条西」は入力では「北1条西」と書かれる(漢数字1文字を算用数字に1:1で畳むと、長さが変わらないので残りの番地部分の切り出しが壊れない)。東京にも「大字宮」のような大字つき町字が33行残っている(島しょ部)。そして廃止された町字のレコードも配布に残るので、ablt_date(廃止日)が空の行だけを現行と見なす。
結: 「東京都千代田区内幸町1丁目1-1」がJSONになった
こうしてできた lookup.py に住所を渡すと、こう返る。
$ python3 address-normalize/lookup.py "東京都千代田区内幸町1丁目1-1"
{
"pref": "東京都",
"city": "千代田区",
"lg_code": "131016",
"town": "内幸町1丁目",
"machiaza_id": "0001001",
"rest": "1-1",
"matched": true
}
(2026-09-27実測。lg_codeは全国地方公共団体コード、machiaza_idは市区町村内の町字ID。この2つで名前の揺れに依存しない一意の鍵になる。)
今日の持ち帰りは3つ。
- 政府データの入口は一つと思うな。 原本ホストが403でも、カタログのフィードを読めばミラーや別配布が見つかることがある。
- 表記ゆれは「正」の側にもある。 正本のマスタ内部でさえ表記が混在する。正規化とは、比較の両側を同じ規則で畳むことだ。
- 一意にしたければ名前ではなくコードで持て。 lg_codeとmachiaza_idの組なら、漢数字だろうが全角だろうが関係ない。
なお番地・号の正規化と緯度経度の付与はこのスキルの対象外で、そこまで必要ならデジタル庁のabr-geocoderというOSSがある。kurashi-skillは公開開発中。リポジトリはここ → https://github.com/tahodev/kurashi-skill