住所入力・電話番号入力フォームのあれこれ

住所入力・電話番号入力フォームを作ったときのあれこれ。

# 郵便番号から住所を補完する

[Ajaxzip3](https://code.google.com/p/ajaxzip3/) をありがたく使わせていただきましょう。

# 都道府県の並びとグルーピング

世の中には「○○県は××県より上だろう」とか「○○県は××地方じゃない」とか言う人が居るんですよ。気持ちはわからんでもないですが、わかるわけでもないです。~~新潟県は北陸地方に含みますか?(知りません……)~~ ~~北陸3県を中部地方に入れるのは乱暴じゃないですか?(そうかもしれませんけど、そんなこと言われても……)~~

なので順序は [JIS X 0401](http://qiita.com/nappa/items/ffaf1c7d7bbc9784a7f7) に準拠し、グルーピングは[八地方区分](http://www.geocities.jp/geo_net21/chimei/chihokubun/8chiho.html)にしてしまいます。全部歴史のせいにするのです。

デフォルトを「東京都」にしておくサイトをよく見かけますが、地方民はあまりそういうのを好まないようです。何も考えずに一番先頭の「北海道」をデフォルトにしておくと北海道の千代田区在住なんていう人が出現します。なので、デフォルトは未選択状態にしておきましょう。

```html
<select name="都道府県">
<option value="">(選択してください)</option>
<optgroup label="北海道">
  <option value="北海道">北海道</option>
</optgroup>
<optgroup label="東北">
  <option value="青森県">青森県</option>
  <option value="秋田県">秋田県</option>
  <option value="岩手県">岩手県</option>
  <option value="山形県">山形県</option>
  <option value="宮城県">宮城県</option>
  <option value="福島県">福島県</option>
</optgroup>
<optgroup label="関東">
  <option value="茨城県">茨城県</option>
  <option value="栃木県">栃木県</option>
  <option value="群馬県">群馬県</option>
  <option value="埼玉県">埼玉県</option>
  <option value="千葉県">千葉県</option>
  <option value="東京都">東京都</option>
  <option value="神奈川県">神奈川県</option>
</optgroup>
<optgroup label="中部">
  <option value="新潟県">新潟県</option>
  <option value="富山県">富山県</option>
  <option value="石川県">石川県</option>
  <option value="福井県">福井県</option>
  <option value="山梨県">山梨県</option>
  <option value="長野県">長野県</option>
  <option value="岐阜県">岐阜県</option>
  <option value="静岡県">静岡県</option>
  <option value="愛知県">愛知県</option>
  <option value="三重県">三重県</option>
</optgroup>
<optgroup label="近畿">
  <option value="滋賀県">滋賀県</option>
  <option value="京都府">京都府</option>
  <option value="大阪府">大阪府</option>
  <option value="兵庫県">兵庫県</option>
  <option value="奈良県">奈良県</option>
  <option value="和歌山県">和歌山県</option>
</optgroup>
<optgroup label="中国">
  <option value="鳥取県">鳥取県</option>
  <option value="島根県">島根県</option>
  <option value="岡山県">岡山県</option>
  <option value="広島県">広島県</option>
  <option value="山口県">山口県</option>
</optgroup>
<optgroup label="四国">
  <option value="徳島県">徳島県</option>
  <option value="香川県">香川県</option>
  <option value="愛媛県">愛媛県</option>
  <option value="高知県">高知県</option>
</optgroup>
<optgroup label="九州・沖縄">
  <option value="福岡県">福岡県</option>
  <option value="佐賀県">佐賀県</option>
  <option value="長崎県">長崎県</option>
  <option value="熊本県">熊本県</option>
  <option value="大分県">大分県</option>
  <option value="宮崎県">宮崎県</option>
  <option value="鹿児島県">鹿児島県</option>
  <option value="沖縄県">沖縄県</option>
</optgroup>
</select>
```

# Shift_JIS に含まれない文字を弾く

入力された住所は多分ラベル印字ソフトの類で出力すると思うんですが、そういうツールでマトモなものを見たことがないですよね。

なので罠を避けるため、Shift_JIS に含まれない文字をとりあえずバリデーションで弾いておきます。

Ruby 2.1 ならこんな感じでチェックできますよ。

```rb
class String
  def shift_jis_compatible?
    begin
      self.encode('Shift_JIS')
      return true
    rescue Encoding::InvalidByteSequenceError, Encoding::UndefinedConversionError => e
      return false
    end
  end
end

p "あ".shift_jis_compatible? #=> true
p "①".shift_jis_compatible? #=> false
p "﨑".shift_jis_compatible? #=> false
p "\u2668".shift_jis_compatible? #=> false
```

# 入力は極力広く受け入れる

1バイト文字で入力された番地を「全角で入力してください」などとバリデーションで弾くような、意識の低いサイトになってはいけません。英数字はサーバサイドで1バイト文字に揃え、ユーザが意識せずに済むようにしてさし上げましょう。

# 郵便番号を使った簡易チェック

* 郵便番号の示す住所と、文字として入力された住所が合致するかどうかをチェック
* 郵便番号の示す住所に続くもの (番地・マンション名など) が入力されているかをチェック

これらのチェックにひっかかった場合には警告を出すようにしておきます。(バリデーションで弾くのではありません。郵便番号DBが誤っている場合を救済するため。)

# 電話番号のバリデーション

電話番号のバリエーションは沼なので下手に手を出すとひどい目にあいます。がんばらないのが吉です。

## お手軽なチェックロジック

* 先頭1桁目は0
* 先頭2桁が00は不可
* 10桁 または 11桁の数字 なら OK とする

普通はこれで十分。

## がんばるチェックロジック

上記のものに加えて、

* 先頭1桁は必ず「0」
* 先頭「00」は不可
* 先頭「010」「020」「030」「040」「0120」「0570」「0990」「0800」は不可
* 長さは 070、080、090、050 のとき、11桁、それ以外は 10桁とする

を追加。

## もっとがんばるチェックロジック

市外局番には存在するものと、そうでないものがあります。

たとえば、

* 03-5320-xxxx : ある
* 03-6225-xxxx : ある
* 03-3000-xxxx : ない
* 03-4532-xxxx : ない

というふうに。

このある・なしを判定するには、[総務省の指定状況](http://www.soumu.go.jp/main_sosiki/joho_tsusin/top/tel_number/number_shitei.html) を参照しなければなりません。ここから憎き Excel データをひっぱってきて DB か何かに保存して、それでもって「未指定」「使用不可」になっている市外局番4桁を弾くように実装すると良いでしょう。

__……と思っていた時期もありました__。これ、指定状況が変わるたびに追従しないといけないので大変なんです。ここ最近は 070-xxxx-xxxx が毎月のように変わってます。こんなことやっちゃダメです。マジで。

# 機械的に検知できないケース

上記ではどうしようもないパターンがあります。たとえば……

* 宛名がペンネーム (ポストに書いてある名前と封筒の名前が一致しないので配達先ポストに入れてくれないというトラブルが多発)……人力でチェックしてユーザに修正してもらう。
* 郵便局留め (保管期間を過ぎて返送されてくるなど、トラブルが多い)……人力でチェックしてユーザに修正してもらう。
* 私書箱宛て (保管期間を過ぎて捨てられてしまう、私書箱が閉鎖されていて届かない、などトラブルが多い)……人力でチェックしてユーザに修正してもらう
* 公営団地の「○号棟」の書き忘れ、「○号室」の数字ミス、マンション名漏れ……人力でチェックしてユーザに修正してもらう。
* 本人が捨ててた(意外によくある。DMといっしょに捨てちゃうんだよね。茶封筒や白封筒だとよく起きる)……記念切手を使って目立たせたり、カラー封筒を使うことである程度回避できる。簡易書留(通常送料プラス350円)を使えば完全排除できる。
* 家族がこっそり捨ててた(簡易書留を使ってもこれは避けられない)……本人限定郵便(簡易書留プラス100円)を使えば防げる。

工夫して防ぎましょう。