ハイフン無しの電話番号をハイフン付の形式に変換してみる

# 概要

システムの移行で元々ハイフン無しの電話番号やFAX番号をハイフン有り形式（3分割）に変換する可能性を考慮して、プログラムで変換がかけられないかを考えてみました。

ちなみに「電話番号」とは通称で、正式には「電気通信番号」、つまり電話以外にもFAXやIoT機器にも割り当てることが出来る番号ということで、総務省が所管しています。
市外局番や市内局番の一覧も、同省ホームページからダウンロード出来るんですが、法改正や市区町村合併とかで変更されることがあると思うのでご注意ください。
本稿は2017年8月時点で確認したものになります。

なお、結構認識とか間違ってるかもしれないので、その辺はご容赦くださいm(_ _)m

## 実装対象と実装対象の仕様

- 大前提として、対象は日本国内の電話番号のみとします。
- 仕様や割当状況は総務省ホームページで公開されています。
    - [電話番号に関するQ&A](http://www.soumu.go.jp/main_sosiki/joho_tsusin/top/tel_number/q_and_a.html)
    - [電気通信番号指定状況](http://www.soumu.go.jp/main_sosiki/joho_tsusin/top/tel_number/number_shitei.html)

## 電話番号の種類

`0A0-CDE-FGHJK`形式のみ番号のフォーマット順にしています。それ以外は総務省ホームページで紹介されている順に記載しています。

|電話番号の種類          |フォーマット   |桁数|備考|
|:-----------------------|:--------------|:---|:---|
|固定電話                |`0A-BCDE-XXXX` |10  | Bは原則2～9のみ |
|固定電話                |`0AB-CDE-XXXX` |10  | Cは原則2～9のみ |
|固定電話                |`0ABC-DE-XXXX` |10  | Dは原則2～9のみ |
|固定電話                |`0ABCD-E-XXXX` |10  | Eは原則2～9のみ |
|M2M等専用番号           |`020-CDE-FGHJK`|11  |`C`は1～3と5～9のみ。理由は次行。|
|発信者課金ポケベル      |`020-4DE-FGHJK`|11  | |
|IP電話                  |`050-CDEF-XXXX`|11  |`C`は1～9のみ。|
|UPTサービス/FMCサービス |`060-4DE-FGHJK`|11  |IoT機器とかに割り当てる番号？ たぶん`C`は1～9のみ。|
|携帯電話、PHS           |`070-CDE-FGHJK`|11  |`C`は1～9のみ。|
|携帯電話、PHS           |`080-CDE-FGHJK`|11  |`C`は1～9のみ。|
|携帯電話、PHS           |`090-CDE-FGHJK`|11  |`C`は1～9のみ。|
|着信課金用電話番号      |`0120-DEF-XXX` |10  | |
|着信課金用電話番号      |`0800-DEF-XXX` |10  | |
|情報料代理徴収用電話番号|`0990-DEF-XXX` |10  |いわゆる「ダイヤルQ2」などがこれに該当する。|
|統一番号用電話番号      |`0570-DEF-XXX` |10  | |

- 固定電話の場合`0{市外局番1～4桁}-{市内局番1～4桁}-{加入者番号4桁}`となっており、合わせて10桁、市外局番（国内プレフィックス含む）と市内局番をあわせて6桁固定となっているようです。（画像は総務省に掲載のもの）

![固定電話の場合](http://www.soumu.go.jp/main_content/000270960.gif "固定電話の場合")

- 他にも「010」から始まる国際電話番号プレフィックスや、警察（110）、消防（119）、時報（117）などありますが、今回は実装対象外とします。
- 携帯電話、PHSなど`0A0-CDE-FGHJK`の番号は、初期契約時の事業者を特定できますが、不要なので対象外とします。

ちなみに書いている途中で「オープンデータ化されていないのかな？」と思って検索してみたらされてました。
[電気通信番号指定状況](http://www.data.go.jp/data/dataset/soumu_20160325_0034)
が、上記ページのファイルへのリンクがあるだけでした。定期的にアップデートする仕組みとか作れるといいかなと思ったんですけどね。

# 実装

## どう実装するか？

仕様はある程度理解できました。
固定電話番号についてに、[総務省ホームページ](http://www.soumu.go.jp/main_sosiki/joho_tsusin/top/tel_number/number_shitei.html#kotei-denwa)のExcelファイルを連結すればマスタは作れそうです。

`0A0`で始まる番号については`C`（4桁目）には`0`が入らないようなので、例えば`060CDEFGHJ`と大阪の市外局番`06BCDEFGHJ`を見分けることができそうです。

ということでなんとかできそうなので、まとめます。

### 桁数のチェック

ハイフンを除いて10桁か11桁しか存在しないみたいなので、それ以外は対象外とします。

### 国内プレフィックスのチェック

`0`から始まっていないものは対象外とします。

### プレフィックスがはっきりしているものからチェックする

以下のものはプレフィックスがはっきりしていますので、これらを優先的にチェックします。

- `0A0-CDE-FGHJK`形式
  - M2M等専用番号、発信者課金ポケベル（`020-CDE-FGHJK`）
  - IP電話（`050-CDEF-XXXX`）
  - UPTサービス/FMCサービス（`060-4DE-FGHJK`）
  - 携帯電話、PHS（`070-CDE-FGHJK`、`080-CDE-FGHJK`、`090-CDE-FGHJK`）
- `0ABC-DEF-XXX`形式
  - 着信課金用電話番号（`0120-DEF-XXX`、`0800-DEF-XXX`）
  - 情報料代理徴収用電話番号（`0990-DEF-XXX`）
  - 統一番号用電話番号（`0570-DEF-XXX`）

### 固定電話番号のチェック

2017年8月の時点で、総務省で公開されている固定電話の市外・市内局番のデータは42,691件あります。
流石にこれの判定には時間がかかりそうなので、一番最後にやることにします。

とは言っても、最初6桁で判定が可能なので、データベースで検索する仕組みを作れば問題なさそうです。
なんでもいいのですが、今回は公開されているデータをExcelで統合して、CSVに出力、それをSQLiteに作ったテーブルにインポートしました（SQLiteを選んだのは一番お手軽だったのと他の言語からもアクセスしやすいようにするためです）。ファイル名は`ja_com_spec_master.sqlite3`としています。
もちろんデータに簡単にアクセスできればなんでもいいでの、下図の番号をキーにしたKVSとかに入れておくと高速に処理できると思います。

統合したデータは以下のような感じです。
![ma_list.png](https://qiita-image-store.s3.amazonaws.com/0/131218/c302f601-1c2d-7093-60ec-dd8174310782.png)

### 設定ファイルにまとめる

ここまでの内容を設定ファイルにまとめて、プログラムで使いやすいようにします。
これもなんでもいいのですが、今回はYAMLにしました。

```yaml:settings.yml
formats:
  - category: "0A0-CDE-FGHJK" # 0A0-で始まる番号のチェック設定
    length: 11
    regexp: "^0(2|[5-9])0[1-9][0-9]+$" # 0A0-0は存在しない
    digits: [3, 4, 4] # 総務省的には[3, 3, 5]っぽいけど

  - category: "0ABC-DEF-GHJK" # 0ABC-で始まる番号のチェック設定
    length: 10
    regexp: "^0(120|800|990|570)[0-9]+$"
    digits: [4, 3, 3]

  - category: "固定電話" # 固定電話の番号のチェック設定
    length: 10
    regexp: "^0[0-9]+$"
    digits: [0, 0, 4] # 0の部分はデータベースに入れています。3つ目が4桁なのは固定です。
```

## プログラム

今回はPHPを使います。
ということで、Githubに上げました。詳しくはそちらを御覧ください。
https://github.com/tomgoodsun/parse_jp_phone_number

なお、テストデータとして、都道府県庁や地方公共自治体の電話番号を使わせて頂きました。一応全件で正しく処理されたみたいなので、たぶん大丈夫。
こちらもネットで公開されている情報になりますが、リポジトリには上げていません。

# まとめ

ここまで来て思った。
Qiitaにすでに同じことやっている人がいた。。。と。
[ハイフンなしの電話番号からハイフン付き電話番号を復元する。](http://qiita.com/kennyj@github/items/dde3880abb5071f649ab)
俺乙。