Google様のライブラリ使いましょう
電話番号のバリデーションを行う場合、
ググると(JSの場合は特に)正規表現で一生懸命頑張ってる記事ばかりヒットしますが、
天下のGoogle様がlibphonenumberなるライブラリを提供してくださっておいでです。
https://github.com/googlei18n/libphonenumber
自分で正規表現書いても辛いだけなので、大人しくこれ使いましょう。
どんだけすごいかはこのスライドが参考になります。
電話番号を扱う技術 by Shota Iguchi
Closure Toolsが分からん・・・
大人しくこれ使いましょうと言ったけど、実はとてもとっつきにくいです。
JS版はClosure Toolsを使ってコンパイルしなければ動かないから。
https://github.com/googlei18n/libphonenumber/tree/master/javascript
How to compile:
- Build Closure's compiler.jar: mvn -DskipTests
- Compile the demo.js and all its dependencies to one file: demo-compiled.js: ant -f javascript/build.xml compile-demo
- Run the compiled demo: javascript/i18n/phonenumbers/demo-compiled.html
僕もまだClosure Toolsは使ったことがなく、今回は敬遠・・・
libphonenumber-jsがオススメ
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
を読み込んでおく
<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で書いてます。)
// ハイフン付きで厳密に確認する場合
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
こういうの全部しっかりとフォーマットしてくれるので、
「フォーマット前後の文字列が一致するか」を確認すればバリデーションがうまく出来るわけです。
validateTel('076-400-0000') // true
validateTel('0764-00-0000') // false
validateTel('1234-56-7890') // false
validateTel('hoge') // false
関数名だけ見るとisValidNumber()
を使いたくなるんだけど、
これはハイフンがどんな風になっててもtrueになっちゃうし、
先頭が0じゃなくても桁数が合ってればtrueになっちゃう。
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')
を使ったバリデーションですが、一部条件の場合にすり抜けてしまうことが分かりました。
validateTel('076') // true
validateTel('0764') // false
なんと、「正しい市外局番のみ」を入れてみるとバリデーション通っちゃいますorz
というわけで、もう少し抜本的に見直したバージョン作りました。
// バリデーション関数
var validateTelNeo = function (value) {
return /^[00]/.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()
に投入してもゼロ追加はしてくれません。そこだけはバリデーションに正規表現/^[00]/.test(value)
を追加して、全角半角どちらでもゼロ開始が必須にしてあげてます。
てわけで、実行結果はこのような感じ。美しいね
main('076-400-0000') // 076-400-0000
main('0764-00-0000') // 076-400-0000
main('07640-00----0----00') // 076-400-0000
main('0764000000') // 076-400-0000
main('1234-56-7890') // ERROR!
main('1234-56-78901') // ERROR!
main('hoge') // ERROR!
ではまた〜。
-
ちなみに、昔は富山市も市外局番「0764」だったんすよ。いつだったか変更になって、金沢も富山も「076」になっちゃった。金沢の電話といえば「0762」から「076」に変わった際、日本文化センターテレフォンショッピングの歌のリズムも少し変わったんですよねーw ↩