Mecabに住所用の辞書を追加する

PHPで都道府県、市区町村、町域名以降の住所分割を高速に行う方法 - 理想未来はどうなった?を参考に

ただし、辞書の生成のところのスクリプトをうまく動かすことができなかったのでPerlで書いて無理やり対応。
それに合わせて処理全体が手作業っぽくなってしまった

作成手順

日本郵政の郵便番号一覧を取得する

http://www.post.japanpost.jp/zipcode/download.html

$ wget http://www.post.japanpost.jp/zipcode/dl/kogaki/lzh/ken_all.lzh

上記で取得した圧縮ファイルを手動で解凍+UTF8へ変換

辞書用CSVを生成する

$ perl conv.pl ken_all.csv ken_dic.csv
※ conv.plの中身については後述

ken_all.csv
: 前項でダウンロードし回答したCSVファイル

ken_dic.csv
: 辞書用CSVファイル

結果、県市区郡町村ごとに単語として登録される。今のところ「大字」と「字」の分離に対応出来ていない

Mecab用の辞書を生成して、ユーザ辞書に追加する

[2011-06-21-3]を参考に。

$ /usr/local/libexec/mecab/mecab-dict-index -d /usr/local/lib/mecab/dic/ipadic -u address.dic -f utf8 -t utf8 ken_dic.csv
$ vi /usr/local/lib/mecab/dic/ipadic/dicrc

;userdic  
userdic = /path/to/address.dic

conv.plの中身

[2011-06-21-3]を参考に。

#!/usr/bin/perl

use strict;  
use warnings;  
use utf8;  
binmode( STDOUT, ":utf8" );  
use encoding 'utf8';  
use Unicode::Normalize;

my ($file1, $file2) = @ARGV;

open( IN,  "$file1" );  
open( OUT, ">$file2" );  
binmode OUT, ":utf8";    ##    <- こっちが正しい

my $i = 0;  
my %address;  
for (<IN>) {  
  chomp($_);

  s/"//go;  
  $_ = NFKC($_);

  my @fields = split(",");

  # 県、市区、町を登録する  
  $address{ $fields[6] }++ if ( $fields[6] );

  if ( $fields[8] ) {  
    $fields[8] =~ s/[(\(〔「~、\d\-].+$//go;  
    $fields[8] =~ s/以下に掲載がない場合//go;

    if ( $fields[8] =~ /(.+?町)(.+)/g ) {  
      $address{$1}++;  
      $address{$2}++;  
    }  
    else {  
      $address{ $fields[8] }++;  
    }  
  }

  if($fields[7] ) {  
    $fields[7] =~ s/[(\(〔「~、\d\-].+$//go;  
    # 区や郡があった場合は、それも分割して考える  
    if ( $fields[7] =~ /(.+市)(.+[区町村])/g ) {  
      $address{$1}++;  
      $address{$2}++;  
    }  
    elsif ( $fields[7] =~ /(.+郡)(.+[町村])/g ) {  
      $address{$1}++;  
      $address{$2}++;  
    }  
    else {  
      $address{ $fields[7] }++ if ( $fields[7] );  
    }  
  }

}

my $key;

foreach $key ( sort keys %address ) {  
  my $len = length($key);

  next if ( !$key );  
  next if ( $len < 2 );  
  next if ( $key =~ /^[県市区町村郡]$/o );

  # 北海道に微妙な地名があったので手動で削除。  
  # これがあると「~市南地名」のような地名が変に切られてしまう  
  next if( $key =~ /^市南$/o);

  print OUT "$key,0,0," . max( -36000, -400 * ( $len ^ 1.5 ) ) . ",名詞,固有名詞,地域,一般,*,*,*,*,$key,*,*,住所辞書\n";  
}

sub max {  
  my $comp = shift @_;  
  my $val  = shift @_;  
  my $max  = $comp;  
  if ( $comp <= $val ) {  
    $max = $val;  
  }  
  return int($max);  
}