Javascriptで電話番号のバリデーションと変換（E.164）に便利なライブラリの紹介

# 今回したいこと
- 日本の電話番号(03-1234-5678)などを、E.164表記(+81312345678)に変換したい
- ついでにバリデーションも出来るといいかも

# 環境
- Node.js

# ライブラリ
- [google-libphonenumber](https://github.com/ruimarinho/google-libphonenumber)

Googleが提供している電話番号をバリデーションと自動フォーマット可能な[libphonenumber](https://github.com/google/libphonenumber)のnpm版である[google-libphonenumber](https://github.com/ruimarinho/google-libphonenumber)を使用します。

# google-libphonenumberの使用方法
## インストール

```
npm install google-libphonenumber
```

## 例１）'202-456-1414'を'US'のE164表記に変換

```js
// Require `PhoneNumberFormat`.
const PNF = require('google-libphonenumber').PhoneNumberFormat;

// Get an instance of `PhoneNumberUtil`.
const phoneUtil = require('google-libphonenumber').PhoneNumberUtil.getInstance();

// Parse number with country code and keep raw input.
const number = phoneUtil.parseAndKeepRawInput('202-456-1414', 'US');

// Format number in the E164 format.
console.log(phoneUtil.format(number, PNF.E164));
// => +12024561414
```

## 例２）全角・半角混合の日本の電話番号をE164表記に変換

```js
// Require `PhoneNumberFormat`.
const PNF = require('google-libphonenumber').PhoneNumberFormat;
// Get an instance of `PhoneNumberUtil`.
const phoneUtil = require('google-libphonenumber').PhoneNumberUtil.getInstance();

const phoneNumbers = [
        '０３―１１１１―２２２２',
        '０３　１１１１　２２２２',
        '（０３）１１１１-２２２２',
        '0312345678',
        '03 1234 5678',
        '03-1234-5678',
        '(03)-1234-5678',
        '09012345678',
        '090-1234-5678',
        '０９０１２３４５６７８',
        '０９０―１２３４―５６７８',
        '0120-123-123'
        ]
const replacedNumbers = phoneNumbers.map(phoneNumber => {
	    const replacedNumber = formatNumber(phoneNumber);
        return replacedNumber;
	})

function formatNumber(str){
    const number = phoneUtil.parseAndKeepRawInput(str, 'JP');
    return phoneUtil.format(number, PNF.E164);
}

console.log(replacedNumbers);

// =>["+81311112222","+81311112222","+81311112222","+81312345678","+81312345678","+81312345678","+81312345678","+819012345678","+819012345678","+819012345678","+819012345678","+81120123123"]
```

# その他の使い方
READMEをそのままのっけています。
バリデーションも出来そうです。

```js

// Require `PhoneNumberFormat`.
const PNF = require('google-libphonenumber').PhoneNumberFormat;

// Get an instance of `PhoneNumberUtil`.
const phoneUtil = require('google-libphonenumber').PhoneNumberUtil.getInstance();

// Parse number with country code and keep raw input.
const number = phoneUtil.parseAndKeepRawInput('202-456-1414', 'US');

// Print the phone's country code.
console.log(number.getCountryCode());
// => 1

// Print the phone's national number.
console.log(number.getNationalNumber());
// => 2024561414

// Print the phone's extension.
console.log(number.getExtension());
// =>

// Print the phone's extension when compared to i18n.phonenumbers.CountryCodeSource.
console.log(number.getCountryCodeSource());
// => FROM_DEFAULT_COUNTRY

// Print the phone's italian leading zero.
console.log(number.getItalianLeadingZero());
// => false

// Print the phone's raw input.
console.log(number.getRawInput());
// => 202-456-1414

// Result from isPossibleNumber().
console.log(phoneUtil.isPossibleNumber(number));
// => true

// Result from isValidNumber().
console.log(phoneUtil.isValidNumber(number));
// => true

// Result from isValidNumberForRegion().
console.log(phoneUtil.isValidNumberForRegion(number, 'US'));
// => true

// Result from getRegionCodeForNumber().
console.log(phoneUtil.getRegionCodeForNumber(number));
// => US

// Result from getNumberType() when compared to i18n.phonenumbers.PhoneNumberType.
console.log(phoneUtil.getNumberType(number));
// => FIXED_LINE_OR_MOBILE

// Format number in the E164 format.
console.log(phoneUtil.format(number, PNF.E164));
// => +12024561414

// Format number in the original format.
console.log(phoneUtil.formatInOriginalFormat(number, 'US'));
// => (202) 456-1414

// Format number in the national format.
console.log(phoneUtil.format(number, PNF.NATIONAL));
// => (202) 456-1414

// Format number in the international format.
console.log(phoneUtil.format(number, PNF.INTERNATIONAL));
// => +1 202-456-1414

// Format number in the out-of-country format from US.
console.log(phoneUtil.formatOutOfCountryCallingNumber(number, 'US'));
// => 1 (202) 456-1414

// Format number in the out-of-country format from CH.
console.log(phoneUtil.formatOutOfCountryCallingNumber(number, 'CH'));
// => 00 1 202-456-1414
```
# （おまけ）ライブラリを使わないでやってみた
最初はgoogle-libphonenumberを知らなかったので、正規表現でやってみました。

```js

const phoneNumbers = [
        '０３―１１１１―２２２２',
        '０３　１１１１　２２２２',
        '（０３）１１１１-２２２２',
        '0312345678',
        '03 1234 5678',
        '03-1234-5678',
        '(03)-1234-5678',
        '09012345678',
        '090-1234-5678',
        '０９０１２３４５６７８',
        '０９０―１２３４―５６７８',
        '0120-123-123'
        ]

const replacedNumbers = phoneNumbers.map(phoneNumber => {
        const replacedNumber = toE164Number(phoneNumber);
        return replacedNumber;
    })


function toE164Number(strVal){
  // 半角変換
  const halfVal = strVal.replace(/[！-～]/g,
    function( tmpStr ) {
      // 文字コードをシフト
      return String.fromCharCode( tmpStr.charCodeAt(0) - 0xFEE0 );
    }
  );
  console.log("halfVal" ,halfVal);
  // 文字の変換
  const number = phoneUtil.parseAndKeepRawInput(halfVal, 'JP');
  console.log(number)
  console.log(phoneUtil.format(number, PNF.E164));
  return halfVal.replace(/[\-\s+()－―]/gi, '').replace('0','+81');
}

```

# 最後に
google-libphonenumberはかなり便利だなと思いました。
ただ電話番号を変換するときにJPなどの国コードを指定しないといけないので、素の電話番号形式から国コードを判定するものがあればいいんですけどね。。