105
77

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-04-23

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:

  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として紹介されてる、
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で書いてます。)

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

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


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)を追加して、全角半角どちらでもゼロ開始が必須にしてあげてます。

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

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!

ではまた〜。

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

105
77
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
105
77

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?