古い記事
ランダムジャンプ
新しい記事
圧縮した郵便番号一覧を使って番号の実在判定をしてみる。

まずは郵便番号の一覧を作成。
「郵便番号データダウンロード - 日本郵便」から「住所の郵便番号(ローマ字)→全国一括」と「事業所の個別郵便番号」を入手し解凍。
7桁郵便番号だけを抜き出す。

■抽出手順:
perl -aF/,/ -lne '$F[1]=~s/\"//g;print$F[1]' ken_all_rome.csv > a
perl -aF/,/ -lne '$F[7]=~s/\"//g;print$F[7]' jigyosyo.csv >> a   
sort -u a > zc.txt

■郵便番号リスト(zc.txt):
0010000
0010010
0010011
...
9998524
9998525
9998531

2011年6月30日更新分だと140486個。ファイルサイズは1.1M。

これらは7桁の整数として見なすことができる。
ということで差分(前後の数の差)表記にして、差が1のが連続した場合はランレングスでさらに圧縮。
例:「5,3,1,1,1,1,1,1,1,21,1,1,7」→「5,3,x7,21,x2,7」

■圧縮ワンライナー:
perl -ne '$d=$_-$p;$s.="$d,";$p=$_;END{
$s=~s%,((1,){2,})%",x".(length($1)/2).","%ge;
$s=~s/,/\n/g;print$s
}' zc.txt > zc-c.txt

ファイルサイズは148Kに。
これだけのことで8分の1ほどに。

実際にこのファイルを読み込んで郵便番号が有効かチェックするプログラム。
読み込んだデータは差分から元の値に戻してビットアレイに格納して判定に使用します(まあハッシュでいいんですけどね)。

■コード(zc.pl):
#!/usr/bin/perl
use strict;
use warnings;

my $bitarray = "";

my $fn = shift @ARGV;
read_c($fn);

while (<>) {
    chomp;
    my $x = $_;
    if (vec($bitarray, $x, 1)) {
        print "yes\n";
    } else {
        print "no\n";
    }
}

sub read_c {
    my ($fn) = @_;
    open(my $fh, "<", $fn) or die;
    my @ns = <$fh>;
    close($fh);
    my $cur = 0;
    foreach my $n (@ns) {
        chomp $n;
        if ($n =~ /^\d+$/) {
            $cur += $n;
            vec($bitarray, $cur, 1) = 1;
        } elsif ($n =~ /^x(\d+)$/) {
            for (my $i = 0; $i < $1; $i++) {
                $cur += 1;
                vec($bitarray, $cur, 1) = 1;
            }
        }
    }
}

■実行例:
% cat a.txt
0000000
1000000
1111111
1500020
1500021
1500022
% ./zc.pl zc-c.txt < a.txt
no
yes
no
no
yes
yes

関連

- 郵便番号データダウンロード - 日本郵便
http://www.post.japanpost.jp/zipcode/download.html
- 電話番号、郵便番号にマッチする真の正規表現 (にぽたん研究所)
http://blog.livedoor.jp/nipotan/archives/51644244.html
- [を] Perl の vec() で bit vector の操作[2011-04-02-4]
- [を] Perlによるビットアレイのセーブ&ロード[2011-07-12-2]