JavaScriptで電話番号のバリデーション＆自動フォーマット

# Google様のライブラリ使いましょう
電話番号のバリデーションを行う場合、
ググると（JSの場合は特に）正規表現で一生懸命頑張ってる記事ばかりヒットしますが、
天下のGoogle様がlibphonenumberなるライブラリを提供してくださっておいでです。
https://github.com/googlei18n/libphonenumber
自分で正規表現書いても辛いだけなので、大人しくこれ使いましょう。
どんだけすごいかはこのスライドが参考になります。
[電話番号を扱う技術 by Shota Iguchi](https://speakerdeck.com/iguchi1124/dian-hua-fan-hao-woxi-uji-shu)

# Closure Toolsが分からん・・・
大人しくこれ使いましょうと言ったけど、実はとてもとっつきにくいです。
JS版は[Closure Tools](https://developers.google.com/closure/)を使ってコンパイルしなければ動かないから。
https://github.com/googlei18n/libphonenumber/tree/master/javascript
> How to compile:
1. Build Closure's compiler.jar: mvn -DskipTests
2. Compile the demo.js and all its dependencies to one file: demo-compiled.js: ant -f javascript/build.xml compile-demo
3. Run the compiled demo: javascript/i18n/phonenumbers/demo-compiled.html

僕もまだClosure Toolsは使ったことがなく、今回は敬遠・・・

# libphonenumber-jsがオススメ
libphonenumberのリポジトリでも[Third-party Portsとして紹介](https://github.com/googlei18n/libphonenumber#third-party-ports)されてる、
JS向けにシンプル化したバージョン「libphonenumber-js」を使うのが一番おすすめです！
https://github.com/catamphetamine/libphonenumber-js
CDNも公開されてるから即使えるよ〜。
https://cdnjs.com/libraries/libphonenumber-js

## サンプルコード1（キッチリ入力させる）
HTMLで`libphonenumber-js.min.js`を読み込んでおく

```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/libphonenumber-js/1.1.10/libphonenumber-js.min.js"></script>
<script src="myapp.js"></script>
```

JSで`libphonenumber`内の各種関数を使ってバリデーション。
（あえてES5で書いてます。）

```js:myapp.js
// ハイフン付きで厳密に確認する場合
var validateTel = function (value) {
  var formattedNumber = new libphonenumber.AsYouType('JP').input(value)
  return value === formattedNumber
}
// ハイフンは無視して良い場合
var validateTelSimple = function (value) {
  return libphonenumber.isValidNumber(value, 'JP')
}
```
### 解説1
`AsYouType('JP')`を使うと、日本の電話番号として
市外局番・市内局番をハイフン区切りで綺麗にフォーマットしてくれるのです。

例えば富山県の電話番号の場合、

* 富山市は`076-400-0000`
* 高岡市は`0766-00-0000`

のように局番の桁数が違うんですねー。[^1]
[^1]: ちなみに、昔は富山市も市外局番「0764」だったんすよ。いつだったか変更になって、金沢も富山も「076」になっちゃった。金沢の電話といえば「0762」から「076」に変わった際、日本文化センターテレフォンショッピングの歌のリズムも少し変わったんですよねーw


こういうの全部しっかりとフォーマットしてくれるので、
「フォーマット前後の文字列が一致するか」を確認すればバリデーションがうまく出来るわけです。

```js

validateTel('076-400-0000') // true
validateTel('0764-00-0000') // false
validateTel('1234-56-7890') // false
validateTel('hoge')         // false
```

関数名だけ見ると`isValidNumber()`を使いたくなるんだけど、
これはハイフンがどんな風になっててもtrueになっちゃうし、
先頭が0じゃなくても桁数が合ってればtrueになっちゃう。

```js

validateTelSimple('076-400-0000')  // true
validateTelSimple('0764-00-0000')  // true
validateTelSimple('07640-00----0----00') // true
validateTelSimple('1234-56-7890')  // true
validateTelSimple('1234-56-78901') // false
validateTelSimple('hoge')          // false
```

これはちょっとキモいので、僕は`AsYouType('JP')`の方を使いたいですねー。。

## サンプルコード2（ゆるい入力＆自動フォーマット）
2018-09-14 追記です。
上記の`AsYouType('JP')`を使ったバリデーションですが、一部条件の場合にすり抜けてしまうことが分かりました。

```js
validateTel('076')  // true
validateTel('0764') // false
```

なんと、「正しい市外局番のみ」を入れてみるとバリデーション通っちゃいますorz
というわけで、もう少し抜本的に見直したバージョン作りました。

```js
// バリデーション関数
var validateTelNeo = function (value) {
  return /^[0０]/.test(value) && libphonenumber.isValidNumber(value, 'JP');
}

// 整形関数
var formatTel = function (value) {
  return new libphonenumber.AsYouType('JP').input(value);
}

var main = function (tel) {
  if (!validateTelNeo(tel)) {
    console.error('ERROR!')
    return
  }
  var formattedTel = formatTel(tel)
  console.log(formattedTel)
  // 以降 formattedTel を使って登録処理など進める
}
```

### 解説2
まずは「人間にハイフン付きできっちり入力させることを求めない」というコンセプトに変えました。例えばプログラムのコーディング規約なんか、ルールに沿って人間がちまちま直す時代は終わって、Linter使って自動フォーマットさせるのが普通じゃないですか。ESLintとかPrettierとか。電話番号だってそうじゃないかと。

本来`AsYouType()`の使い方は、まさにそこなんですよね。「この通りに入力せい！」ではなく「入力したのを綺麗にしてあげるよ」って使い方をすべきだと改心したわけです僕は！

ということで、処理は二段階

* `isValidNumber()`を使ってバリデーション
* バリデーション通ったら`AsYouType()`使って自動フォーマット

この二段階を想定すると、上の「解説1」に書いた`isValidNumber()`のユルさも納得できるのですよ。`AsYouType()`ではハイフンとか全角半角とか混在してても綺麗にフォーマットしてくれるので、「`AsYouType()`に投入してエラーが出ない最低限の条件」だけ満たしてれば、ユーザーの入力は全然ユルくて良いじゃないかと。むしろその方が親切。

体裁はPrettierに任せてプログラマーはビジネスロジックに集中するように、ユーザーはフォームへの入力内容そのものに集中していただきましょう！

駄菓子菓子、`isValidNumber()`で残り唯一カバーできないのが「先頭がゼロでなくても認めてしまう」ってこと。その状態で`AsYouType()`に投入してもゼロ追加はしてくれません。そこだけはバリデーションに正規表現`/^[0０]/.test(value)`を追加して、全角半角どちらでもゼロ開始が必須にしてあげてます。

てわけで、実行結果はこのような感じ。美しいね :sparkles: 

```js
main('076-400-0000')  // 076-400-0000
main('0764-00-0000')  // 076-400-0000
main('07640-00----0----00') // 076-400-0000
main('０76４00０00０')  // 076-400-0000
main('1234-56-7890')  // ERROR!
main('1234-56-78901') // ERROR!
main('hoge')          // ERROR!
```




ではまた〜。