「住所データを整形する」の版間の差分

提供: dococo wiki
ナビゲーションに移動 検索に移動
imported>Webmaster
(ページの作成:「== はじめに == 地図を加工するときに2種類の住所データを比較してプロットしたいことがよくある<br /> 例えば、丁町目ポリゴ...」)
 
imported>Webmaster
6行目: 6行目:
 
#<code>福島県郡山市田村町桜ケ丘1丁目</code>
 
#<code>福島県郡山市田村町桜ケ丘1丁目</code>
 
#<code>福島県郡山市田村町桜ケ丘一丁目</code>
 
#<code>福島県郡山市田村町桜ケ丘一丁目</code>
 +
両方とも意味は合っているので間違っていないけど、EXCELなどのVLOOKUPで引っかけようとすると半角と全角、アラビア数字と漢数字が混ざっているためそう簡単には比較できないようになっている。<br />
 +
日本語の住所表記の性(サガ)というか仕方ないけど、これを綺麗に整形(あるルールに則って文字を変更させる)方法についてPerlを使って説明する<br />
 +
== 異なる住所情報 ==
 +
2つの住所が異なるポイントは以下の条件があると考える<br />
 +
#「ケ」か「ヶ」か「が」か(例:百合ヶ丘/百合が丘)
 +
#「ツ」か「ツ」か
 +
#「ノ」か「ノ」か「の」か「乃」か「之」か
 +
#「12丁目」か「12丁目」か「十二丁目」か「一二丁目」か
 +
#「通り」か「通」か
 +
といろいろありますが、使いながら合わせていくしか有りませんね<br />
  
 
+
== サンプルプログラム ==
 
+
ここではまず<br />
<syntaxhighlight lang="perl">
+
*半角を全角にする
use strict;
+
*アラビア数字を漢数字にする
use warnings;
+
というルールの変換を行いたいと思います
use utf8;
 
 
 
#これで標準出力が自動的にcp932にencodeされる
 
binmode STDOUT , ":encoding(cp932)";
 
 
 
{
 
  use Encode;
 
  use Encode::JP::H2Z;
 
  my $eucjp = Encode::find_encoding('eucjp');
 
  sub hankaku2zenkaku {
 
    my $str = $eucjp->encode(shift);
 
    Encode::JP::H2Z::h2z(\$str);
 
    $eucjp->decode($str);
 
  }
 
  sub zenkaku2hankaku {
 
      my $str = $eucjp->encode(shift);
 
      Encode::JP::H2Z::z2h(\$str);
 
      $eucjp->decode($str);
 
  }
 
}
 
 
 
print hankaku2zenkaku("オンドゥルルラギッタンディスカー!?"), "\n";
 
print zenkaku2hankaku("ウソダドンドコドーン"), "\n";
 
 
 
</syntaxhighlight>
 
----
 
== 文字コードを意識的にプログラムする ==
 
入り口で decode して、内部ではすべて flagged utf8 で扱い、出口で encode する。これがすべてです!とにかくこの基本方針をまもっていれば幸せになれます。
 
という言いつけを守るために、<code>binmode</code>を使わないで意識的に文字コードを考えたら私的には以下のようにするのが良いと感じました。<br />
 
このようにすることで、出力する直前に必要な文字コードに変換して出力するという意識になります。<br />
 
 
 
 
 
<syntaxhighlight lang="perl">
 
use strict;
 
use warnings;
 
use utf8;
 
 
 
{
 
  use Encode;
 
  use Encode::JP::H2Z;
 
  my $eucjp = Encode::find_encoding('eucjp');
 
  sub hankaku2zenkaku {
 
    my $str = $eucjp->encode(shift);
 
    Encode::JP::H2Z::h2z(\$str);
 
    $eucjp->decode($str);
 
  }
 
  sub zenkaku2hankaku {
 
      my $str = $eucjp->encode(shift);
 
      Encode::JP::H2Z::z2h(\$str);
 
      $eucjp->decode($str);
 
  }
 
}
 
 
 
print encode('cp932',hankaku2zenkaku("オンドゥルルラギッタンディスカー!?")), "\n";
 
print encode('cp932',zenkaku2hankaku("ウソダドンドコドーン")), "\n";
 
 
 
</syntaxhighlight>
 
 
 
== 文字も記号も数字も全て半角を全角にする ==
 
いろいろ使って見て分かったことですけど、半角を全角にする場合にはモジュールという便利な物を使う必要がある<br />
 
モジュールには標準モジュールの<code>Encode.pm</code>と別途インストールして使用する<code>Unicode::Japanese</code>および<code>Lingua::JA::Regular::Unicode</code>がある。<br />
 
ここでやりたいこととと異なってきた内容で、標準モジュールの<code>Encode.pm</code>要するに今まで説明した<br />
 
<syntaxhighlight lang="perl">
 
      Encode::JP::H2Z::z2h(\$str);
 
</syntaxhighlight>
 
といった、<code>Encode::JP::H2Z::z2h</code>では全角変換は<span style="color:red">'''カナのみで、数字や記号については変換しない'''</span>事が分かりました。<br />
 
これを回避するために新たに<code>use Unicode::Japanese;</code>を使うと数字や記号も変換します<code>Unicode::Japanese;</code>を使う場合には<code>Unicode::Japanese</code>をインストールしなければなりません。<br />
 
=== Unicode::Japaneseインストール方法 ===
 
<syntaxhighlight lang="perl">
 
$ perl -MCPAN -e shell
 
cpan> install Unicode::Japanese
 
</syntaxhighlight>
 
インストール環境に問題が無ければこれでモジュールがインストールされます。<br />
 
=== サンプルプログラム ===
 
これも'''UTF-8'''で保存する必要がありますので注意が必要です
 
 
<syntaxhighlight lang="perl">
 
<syntaxhighlight lang="perl">
 
#UTF-8で保存する
 
#UTF-8で保存する
96行目: 31行目:
  
 
#$str_hに半角データを入れる
 
#$str_hに半角データを入れる
my $str_h = '012ABCabc!@#アイウガダパ';
+
my $str_h = '福島県郡山市田村町桜ケ丘123丁目';
  
#cp932で表示してみる(1)
+
#Unicode::Japaneseで表示してみるcp932でもsjisでも表示される
print encode('cp932',$str_h),"\n";
+
print Unicode::Japanese->new($str_h)->cp932,"\n";
  
#Unicode::Japaneseで表示してみる(2)cp932でもsjisでも表示される
 
print Unicode::Japanese->new($str_h)->cp932,"\n";
 
  
#(1)と(2)は同じ結果になる、表示ルールを変えただけ
+
#数字を漢数字に変換
 +
  # 数字は半角にそろえておく
 +
    $str_h =~ y/1234567890/1234567890/;
 +
  # 単独の0は「ゼロ」に書き換える
 +
    $str_h =~ s/(?<!\d)0(?!\d)/ゼロ/g;
 +
  # 桁区切りのコンマを取っておく
 +
    $str_h =~ s/(?<=\d),(?=(\d\d\d)+(?!\d))//g;
 +
  # 4桁ごとに区切って万億兆を挿入
 +
    $str_h =~ s/(?<=\d)(?=\d\d\d\d(?!\d))/万/g;
 +
    $str_h =~ s/(?<=\d)(?=\d\d\d\d(?=万))/億/g;
 +
    $str_h =~ s/(?<=\d)(?=\d\d\d\d(?=億))/兆/g;
 +
  # 下から1桁ずつ十百千を挿入
 +
    $str_h =~ s/(?<=\d)(?=\d(?!\d))/十/g;
 +
    $str_h =~ s/(?<=\d)(?=\d(?!\d))/百/g;
 +
    $str_h =~ s/(?<=\d)(?=\d(?!\d))/千/g;
 +
  # 0になってる桁を削除
 +
    $str_h =~ s/0[十百千]//g;
 +
    $str_h =~ s/億0万/億/g;
 +
    $str_h =~ s/兆0億/兆/g;
 +
    $str_h =~ s/0//g;
 +
  # 十百には1をつけない
 +
    $str_h =~ s/1([十百])/$1/g;
 +
  # 各桁を漢数字に書き換え
 +
    $str_h =~ y/123456789/一二三四五六七八九/;
  
#h2z(半角から全角)
+
#h2z(半角から全角)->cp932を->getとするとutf8で保存される
#通常の表示方法
 
#->cp932を->getとするとutf8で保存される
 
 
print Unicode::Japanese->new($str_h)->h2z->cp932,"\n";
 
print Unicode::Japanese->new($str_h)->h2z->cp932,"\n";
  
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 
これを実行した場合以下の結果になります<br />
 
これを実行した場合以下の結果になります<br />
<code>012ABCabc!@#アイウガダパ</code><br />
+
<code>福島県郡山市田村町桜ケ丘123丁目</code><br />
<code>012ABCabc!@#アイウガダパ</code><br />
+
<code>福島県郡山市田村町桜ケ丘百二十三丁目</code><br />
これで、半角を全角にすることが出来ます
+
まずは、これでVLOOKUPあわせを行いたいと思います。
 +
 
  
 
<!-- カテゴリに追加するページ名を記入 -->
 
<!-- カテゴリに追加するページ名を記入 -->
 
[[Category:Perl|じゅうしょでーたをせいけいする]]
 
[[Category:Perl|じゅうしょでーたをせいけいする]]

2016年8月13日 (土) 11:57時点における版

はじめに

地図を加工するときに2種類の住所データを比較してプロットしたいことがよくある
例えば、丁町目ポリゴンデータとデータを測定した際の住所を重ね合わせる場合、世間的には11桁コードというデータ(要するに住所を数字化した物)で突合させるらしい。しかし、費用がかかるので出来るだけ安く突合できないか考えてみた

住所合わせ

よく問題になるのが住所の不整合。典型的な例では以下のような場合

  1. 福島県郡山市田村町桜ケ丘1丁目
  2. 福島県郡山市田村町桜ケ丘一丁目

両方とも意味は合っているので間違っていないけど、EXCELなどのVLOOKUPで引っかけようとすると半角と全角、アラビア数字と漢数字が混ざっているためそう簡単には比較できないようになっている。
日本語の住所表記の性(サガ)というか仕方ないけど、これを綺麗に整形(あるルールに則って文字を変更させる)方法についてPerlを使って説明する

異なる住所情報

2つの住所が異なるポイントは以下の条件があると考える

  1. 「ケ」か「ヶ」か「が」か(例:百合ヶ丘/百合が丘)
  2. 「ツ」か「ツ」か
  3. 「ノ」か「ノ」か「の」か「乃」か「之」か
  4. 「12丁目」か「12丁目」か「十二丁目」か「一二丁目」か
  5. 「通り」か「通」か

といろいろありますが、使いながら合わせていくしか有りませんね

サンプルプログラム

ここではまず

  • 半角を全角にする
  • アラビア数字を漢数字にする

というルールの変換を行いたいと思います

#UTF-8で保存する
use strict;
use warnings;
use utf8;
use Encode;#これがないと「Undefined subroutine &main::encode called at」が出る
use Unicode::Japanese;

#$str_hに半角データを入れる
my $str_h = '福島県郡山市田村町桜ケ丘123丁目';

#Unicode::Japaneseで表示してみるcp932でもsjisでも表示される
print Unicode::Japanese->new($str_h)->cp932,"\n";


#数字を漢数字に変換
  # 数字は半角にそろえておく
    $str_h =~ y/1234567890/1234567890/;
  # 単独の0は「ゼロ」に書き換える
    $str_h =~ s/(?<!\d)0(?!\d)/ゼロ/g; 
  # 桁区切りのコンマを取っておく
    $str_h =~ s/(?<=\d),(?=(\d\d\d)+(?!\d))//g;
  # 4桁ごとに区切って万億兆を挿入
    $str_h =~ s/(?<=\d)(?=\d\d\d\d(?!\d))/万/g;
    $str_h =~ s/(?<=\d)(?=\d\d\d\d(?=万))/億/g;
    $str_h =~ s/(?<=\d)(?=\d\d\d\d(?=億))/兆/g;
  # 下から1桁ずつ十百千を挿入
    $str_h =~ s/(?<=\d)(?=\d(?!\d))/十/g;
    $str_h =~ s/(?<=\d)(?=\d(?!\d))/百/g;
    $str_h =~ s/(?<=\d)(?=\d(?!\d))/千/g;
  # 0になってる桁を削除
    $str_h =~ s/0[十百千]//g;
    $str_h =~ s/億0万/億/g;
    $str_h =~ s/兆0億/兆/g;
    $str_h =~ s/0//g;
  # 十百には1をつけない
    $str_h =~ s/1([十百])/$1/g;
  # 各桁を漢数字に書き換え
    $str_h =~ y/123456789/一二三四五六七八九/;

#h2z(半角から全角)->cp932を->getとするとutf8で保存される
print Unicode::Japanese->new($str_h)->h2z->cp932,"\n";

これを実行した場合以下の結果になります
福島県郡山市田村町桜ケ丘123丁目
福島県郡山市田村町桜ケ丘百二十三丁目
まずは、これでVLOOKUPあわせを行いたいと思います。