モノノフ日記

普通の日記です

郵便番号から都道府県を判定する

今作ってるモノに郵便番号から都道府県の判定する必要が出てきたので調べてみました。

Googleで調べてみてわかったこと

郵便番号の上2桁から都道府県を判定してる記事を見つけました。その中に気になる記述が。

最初は、以下のサイトから郵便番号データ全件をダウンロードして、
郵便番号全桁から判断しようと思ったのですが、郵便番号って、1つの郵便番号に複数の住所が紐づいていて、
かつ、その住所が2つの都道府県に跨っているケースがあることが分かりました。

中級プログラマの自宅でPHP ブログ 郵便番号から都道府県を判定するには?

郵便番号が同じでも違う都道府県を指してる場合があるとのこと。ホントかな?と思いながらもう少し調べてるとこんな記事を発見。

おー、ホントにありました。でも記事が2007年なので、もしかしたらデータが更新されているかもと思い実データでチェックしてみました。

実際のデータを使って調査してみる

全国の住所の郵便番号データは日本郵便のページからCSV形式でダウンロードが可能です。

今回は、読み仮名データの促音・拗音を小書きで表記している全国一括のデータ(http://www.post.japanpost.jp/zipcode/dl/kogaki/lzh/ken_all.lzh)を使いました。

データ取得・解凍
$ wget http://www.post.japanpost.jp/zipcode/dl/kogaki/lzh/ken_all.lzh
$ lha x ken_all.lzh
文字コード変換

文字コードSJISだったのでUTF8に変換します。

$ iconv -f sjis -t utf-8 ken_all.csv > ken_all_utf8.csv
データ抽出

サクッとawk使って処理してみました。重複している郵便番号と都道府県名だけを抜き出してます。

$ gawk -F, '{print $3,$7}'< ken_all_utf8.csv | tr -d '"' | sort -k 1 | uniq -D -w 7 | sort -u | uniq -D -w 7 > post_pref_list.txt

post_pref_list.txtの中身は下記のようになりました。

4980000 愛知県
4980000 三重県
6180000 京都府
6180000 大阪府
8710000 大分県
8710000 福岡県

2007年から重複しているデータについては特に変更がないみたいです。今回、自分が実装する案件では正確なデータは必要とされていないので郵便番号上2桁で判定するアイデアをいただきました。

郵便番号上2桁と都道府県をリストにします。

$ gawk -F, '{print substr($3,0,3),$7}' < ken_all_utf8.csv | tr -d '"' | sort -u > post2pref.txt

作成したpost2prefファイルをdropbox(http://dl.dropbox.com/u/148481/post2pref.txt)にアップしました。中級プログラマの自宅でPHP ブログ 郵便番号から都道府県を判定するには?で書かれてる表と同じ内容ですね。

実装

判定処理をJavaScriptで実装してみました。

function post2pref(zipcode) {
  var pref;
  switch (true) {
    case /^0(0|[4-9])/.test(zipcode):
      pref = '北海道';
      break;
    case /^01/.test(zipcode):
      pref = '秋田県';
      break;
    case /^02/.test(zipcode):
      pref = '岩手県';
      break;
    case /^03/.test(zipcode):
      pref = '青森県';
      break;
    case /^1/.test(zipcode):
    case /^20/.test(zipcode):
      pref = '東京都';
      break;
    case /^2[1-5]/.test(zipcode):
      pref = '神奈川県';
      break;
    case /^2[6-9]/.test(zipcode):
      pref = '千葉県';
      break;
    case /^3[0-1]/.test(zipcode):
      pref = '茨城県';
      break;
    case /^32/.test(zipcode):
      pref = '栃木県';
      break;
    case /^3[3-6]/.test(zipcode):
      pref = '埼玉県';
      break;
    case /^37/.test(zipcode):
      pref = '群馬県';
      break;
    case /^3[8-9]/.test(zipcode):
      pref = '長野県';
      break;
    case /^40/.test(zipcode):
      pref = '山梨県';
      break;
    case /^4[1-3]/.test(zipcode):
      pref = '静岡県';
      break;
    case /^4[4-9]/.test(zipcode):
      pref = '愛知県';
      break;
    case /^50/.test(zipcode):
      pref = '岐阜県';
      break;
    case /^51/.test(zipcode):
      pref = '三重県';
      break;
    case /^52/.test(zipcode):
      pref = '滋賀県';
      break;
    case /^5[3-9]/.test(zipcode):
      pref = '大阪府';
      break;
    case /^6[0-2]/.test(zipcode):
      pref = '京都府';
      break;
    case /^63/.test(zipcode):
      pref = '奈良県';
      break;
    case /^64/.test(zipcode):
      pref = '和歌山県';
      break;
    case /^6[5-7]/.test(zipcode):
      pref = '兵庫県';
      break;
    case /^68/.test(zipcode):
      pref = '鳥取県';
      break;
    case /^69/.test(zipcode):
      pref = '島根県';
      break;
    case /^7[0-1]/.test(zipcode):
      pref = '岡山県';
      break;
    case /^7[2-3]/.test(zipcode):
      pref = '広島県';
      break;
    case /^7[4-5]/.test(zipcode):
      pref = '山口県';
      break;
    case /^76/.test(zipcode):
      pref = '香川県';
      break;
    case /^77/.test(zipcode):
      pref = '徳島県';
      break;
    case /^78/.test(zipcode):
      pref = '高知県';
      break;
    case /^79/.test(zipcode):
      pref = '愛媛県';
      break;
    case /^8[0-3]/.test(zipcode):
      pref = '福岡県';
      break;
    case /^84/.test(zipcode):
      pref = '佐賀県';
      break;
    case /^85/.test(zipcode):
      pref = '長崎県';
      break;
    case /^86/.test(zipcode):
      pref = '熊本県';
      break;
    case /^87/.test(zipcode):
      pref = '大分県';
      break;
    case /^88/.test(zipcode):
      pref = '宮崎県';
      break;
    case /^89/.test(zipcode):
      pref = '鹿児島県';
      break;
    case /^90/.test(zipcode):
      pref = '沖縄県';
      break;
    case /^91/.test(zipcode):
      pref = '福井県';
      break;
    case /^92/.test(zipcode):
      pref = '石川県';
      break;
    case /^93/.test(zipcode):
      pref = '富山県';
      break;
    case /^9[4-5]/.test(zipcode):
      pref = '新潟県';
      break;
    case /^9[6-7]/.test(zipcode):
      pref = '福島県';
      break;
    case /^98/.test(zipcode):
      pref = '宮城県';
      break;
    case /^99/.test(zipcode):
      pref = '山形県';
      break;
    default:
      pref = 'unknown';
  }
  return pref;
}

まとめ

2つの都道府県が重複している3つの番号だけ例外的な処理を加えれば、もっと柔軟な処理も可能だと思います。正確性を求められないなら今回みたいな実装でよいんじゃないでしょうか。