1#!/usr/local/bin/perl 2# ---------------------------------------------------------------- # 3# AjaxZip 2.0 - Ajax郵便番号→住所自動入力フォーム(CGI不要版)用 4# 郵便番号一覧 CSV ファイルを JSON 形式に変換するスクリプト 5# http://www.kawa.net/works/ajax/ajaxzip2/ajaxzip2.html 6# (c) 2001-2007 Kawasaki Yusuke. All rights reserved. 7# ---------------------------------------------------------------- # 8 use strict; 9 use utf8; 10 use Encode; # 文字コード変換モジュール弾 11 use lib qw( lib ); 12 use JSON; # JSON.pm がデフォルトです 13# use JSON::Syck; # JSON::Syckがあれば利用可能です 14# ---------------------------------------------------------------- # 15 my $VERSION = '2.11'; 16 my $CSV_ENC = 'CP932'; # CSVファイルのエンコーディング 17 my $JSON_ENC = 'utf8'; # JSONファイルのエンコーディング 18 my $DISP_ENC = 'utf8'; # 表示用のエンコーディング 19 my $CSV_FILE = 'ken_all.csv'; # 入力元CSVファイル名(デフォルト) 20 my $CSV_JIGYO = 'jigyosyo.csv'; # 事業所要郵便番号CSVファイル(オプション) 21 my $JSON_BASE = '../data/zip-%s.json'; # 出力先JSONファイル名 22# ---------------------------------------------------------------- # 23 # local $| = 1; 24 &main( @ARGV ); 25# ---------------------------------------------------------------- # 26sub main { 27 my $csvfile = shift || $CSV_FILE; 28 my $csvjigyo = shift || $CSV_JIGYO; 29 30 my $out = {}; 31 &read_ken_all( $out, $csvfile ); 32 &read_jigyosyo( $out, $csvjigyo ) 33 &write_json( $out ); 34} 35# ---------------------------------------------------------------- # 36# 読み仮名データの促音・拗音を小書きで表記したもの 37# http://www.post.japanpost.jp/zipcode/dl/kogaki.html 38# http://www.post.japanpost.jp/zipcode/dl/kogaki/lzh/ken_all.lzh 39# ---------------------------------------------------------------- # 40sub read_ken_all { 41 my $out = shift or return; 42 my $csvfile = shift; 43 my $prev = ""; 44 my $c = 0; 45 46 print STDERR "ken_all:\t$csvfile\n"; 47 open( CSV, $csvfile ) or die "$! - $csvfile\n"; 48 while ( my $iline = <CSV> ) { 49 last if ( $iline =~ /^\x1a/ ); # EOF 50 51 # UTF-8コードで処理する 52 $iline = Encode::decode( $CSV_ENC, $iline ); 53 54 # CSVとはいっても「,」の文字は住所には利用されていないので簡易処理 55 my @r = split( ",", $iline ); 56 s/^"(.*)"$/$1/s foreach ( @r ); 57 58 # 第1・3・10・15カラムは、確実に数字のみのハズ 59 if ( $r[0] !~ m#^\d{5}$# || 60 $r[2] !~ m#^\d{7}$# || 61 $r[9] !~ m#^\d{1}$# || 62 $r[14] !~ m#^\d{1}[\r\n]+$# ) { 63 die "Invalid Data Source: $csvfile (ken_all.csv)\n$iline\n"; 64 } 65 66 # 全角かっこ『(』が入る場合は、フリガナからも半角かっこ『(』を除外 67 if ( $r[8] =~ s/((.)+$//s ) { 68 $r[5] =~ s/\([^\(]+$//s; 69 } 70 71 # 岩手県 和賀郡西和賀町 杉名畑44地割 72 # 岩手県 和賀郡西和賀町 穴明22地割、穴明23地割 73 # 岩手県 九戸郡洋野町 種市第15地割~第21地割 74 $r[8] =~ s/(第)?(0|1|2|3|4|5|6|7|8|9)+地割.*$//s; 75 76 #『以下に掲載がない場合』等は削除してしまう 77 if ( $r[8] =~ /(^以下に掲載がない場合 78 |の次に番地がくる場合 79 |一円 80 |) 81 |、(.)* 82 )$/xs ) { 83 $r[8] = ""; 84 $r[5] = ""; 85 } 86 87 # 郵便番号上位3桁 88 my $zip3 = ( $r[2] =~ /^([0-9]{3})/ )[0]; 89 90 # 都道府県ID・市町村名・町域名のみ記録 91 $out->{$zip3} ||= {}; 92 my $pref = int($r[0]/1000); 93 $out->{$zip3}->{$r[2]} ||= [ $pref, $r[7], $r[8] ]; 94 95 # 都道府県が変わったら、画面に都道府県名を表示する 96 if ( $prev ne $pref ) { 97 $prev = $pref; 98 print STDERR " $c lines\n" if $c; 99 my $v = sprintf( "%s \t", $r[6] ); 100 $v = Encode::encode( $DISP_ENC, $v ); 101 print STDERR $v; 102 $c = 0; 103 } 104 print STDERR "." if ( $c ++ % 200 == 0 ); 105 } 106 print STDERR " $c lines\n" if ( $c > 0 ); 107 close( CSV ); 108 $out; 109} 110# ---------------------------------------------------------------- # 111# 事業所の個別郵便番号 112# http://www.post.japanpost.jp/zipcode/dl/jigyosyo/index.html 113# http://www.post.japanpost.jp/zipcode/dl/jigyosyo/lzh/jigyosyo.lzh 114# ---------------------------------------------------------------- # 115sub read_jigyosyo { 116 my $out = shift or return; 117 my $csvjigyo = shift or return; 118 my $prev = ""; 119 my $c = 0; 120 121 return unless ( -f $csvjigyo ); 122 123 print STDERR "jigyosyo:\t$csvjigyo\n"; 124 open( JIGYO, $csvjigyo ) or die "$! - $csvjigyo\n"; 125 while ( my $iline = <JIGYO> ) { 126 last if ( $iline =~ /^\x1a/ ); # EOF 127 128 # UTF-8コードで処理する 129 $iline = Encode::decode( $CSV_ENC, $iline ); 130 131 # CSVとはいっても「,」の文字は住所には利用されていないので簡易処理 132 my @r = split( ",", $iline ); 133 s/^"(.*)"$/$1/s foreach ( @r ); 134 135 # 第1・8・11・13カラムは、確実に数字のみのハズ 136 if ( $r[0] !~ m#^\d{5}$# || 137 $r[7] !~ m#^\d{7}$# || 138 $r[10] !~ m#^\d{1}$# || 139 $r[12] !~ m#^\d{1}[\r\n]+$# ) { 140 die "Invalid Data Source: $csvjigyo (jigyosyo.csv)\n$iline\n"; 141 } 142 143 # 全角かっこ『()』や『1F~9F』を削除 144 $r[6] =~ s/(.*)$//s; 145 $r[6] =~ s/(-)?((0|1|2|3|4|5|6|7|8|9)+(F|階|~|、)+)+ 146 (0|1|2|3|4|5|6|7|8|9)+(F|階)$//sx; 147 148 # 郵便番号上位3桁 149 my $zip3 = ( $r[7] =~ /^([0-9]{3})/ )[0]; 150 151 # 都道府県ID・市町村名・町域名・番地を記録 152 $out->{$zip3} ||= {}; 153 my $pref = int($r[0]/1000); 154 $out->{$zip3}->{$r[7]} ||= [ $pref, $r[4], $r[5], $r[6] ]; 155 156 # 都道府県が変わったら、画面に都道府県名を表示する 157 if ( $prev ne $pref ) { 158 $prev = $pref; 159 print STDERR " $c lines\n" if $c; 160 my $v = sprintf( "%s \t", $r[3] ); 161 $v = Encode::encode( $DISP_ENC, $v ); 162 print STDERR $v; 163 $c = 0; 164 } 165 print STDERR "." if ( $c ++ % 200 == 0 ); 166 } 167 print STDERR " $c lines\n" if ( $c > 0 ); 168 close( JIGYO ); 169 $out; 170} 171# ---------------------------------------------------------------- # 172# 郵便番号上位3桁ごとにJSONファイルに書き出していく 173# ---------------------------------------------------------------- # 174sub write_json { 175 my $out = shift or return; 176 my $prev = ""; 177 my $c = 0; 178 179 my $use_syck = $JSON::Syck::VERSION; 180 my $use_json = $JSON::VERSION unless $use_syck; 181 my $new_json = (( $use_json =~ /^([\d\.]+)/ )[0] >= 2.0 ) if $use_json; 182 183 print STDERR "module: \tJSON.pm ($use_json)\n" if $use_json; 184 print STDERR "module: \tJSON::Syck ($use_syck)\n" if $use_syck; 185 print STDERR "json: \t$JSON_BASE\n"; 186 187 foreach my $zip3 ( sort keys %$out ) { 188 # JSONフォーマットでダンプする 189 my $data = $out->{$zip3}; 190 my $dump = $use_syck ? JSON::Syck::Dump($data) : 191 $new_json ? to_json($data) : objToJson($data); 192 193 # JSONファイル名の決定 194 my $jsonfile = sprintf( $JSON_BASE, $zip3 ); 195 196 # JSONファイル設置ディレクトリの確認 197 my $jsondir = ( $jsonfile =~ m#^(.*/)[^/]+$# )[0]; 198 die "$! - $jsondir\n" if ( $jsondir && ! -d $jsondir ); 199 200 # JSONファイルに書き出す 201 open( JSON, "> $jsonfile" ) or die "$! - $jsonfile\n"; 202 $dump = Encode::encode( $JSON_ENC, $dump ) if $new_json; 203 print JSON $dump, "\n"; 204 close( JSON ); 205 206 # 郵便番号上位1桁が変わったら表示する 207 my $zip1 = ( $zip3 =~ /^([0-9])/ )[0]; 208 if ( $prev ne $zip1 ) { 209 $prev = $zip1; 210 print STDERR " $c files\n" if $c; 211 printf STDERR ( "$JSON_BASE ", "$zip1**" ); 212 $c = 0; 213 } 214 print STDERR "." if ( $c ++ % 10 == 0 ); 215 } 216 print STDERR " $c files\n" if ( $c > 1 ); 217} 218# ---------------------------------------------------------------- # 219