phonelibを利用して電話番号を上手に扱う

こんにちは。beaglesoftの真鍋です。

ココ最近はRailsを利用しています。decodeが開催されているのを横目にしながらRailsでアプリケーションを書いているのですが、むかしに比べるとすごく早く機能を実現できるなぁと感じるようになって気に入ってきました。

さて、RailsといえばGemです。便利なGemをいかに組み合わせてやりたいことを実現するかが肝です。今回は電話番号を上手に扱うGemがあったのでちょっとまとめてみました。

phoelibとは

phonelibは電話番号に関する検証を行うライブラリで、Googleが公開しているgoogle/libphonenumber: Google's common Java, C++ and JavaScript library for parsing, formatting, and validating international phone numbers. をRubyで利用できるようにしたライブラリです。

daddyz/phonelib: Ruby gem for phone validation and formatting using google libphonenumber library data

主な機能

主な機能として電話番号の検証や電話番号に関する情報を取得することができます。

電話番号の検証

電話番号の検証は国を指定して行います。ここで指定する国コードはISO 3166-1 alpha-2 - Wikipediaを参照してください。

日本の場合はjpを指定します。

> Phonelib.valid_for_country?(03-1234-5678, :jp)
=> true
> Phonelib.invalid_for_country?(03-1234-5678, :jp)
=> false

ちょっといろいろ試してみる

# フリーダイアル
>> >> Phonelib.valid_for_country?('0123-444-444', :jp)
=> true

# IP電話
>> >> Phonelib.valid_for_country?('050-1234-5678', :jp)
=> true

# 以下携帯電話
>> >> Phonelib.valid_for_country?('070-1234-5678', :jp)
=> true
>> >> Phonelib.valid_for_country?('080-1234-5678', :jp)
=> true
>> >> Phonelib.valid_for_country?('090-1234-5678', :jp)
=> true

電話番号のパース

電話番号文字列から電話番号をパースすることができます。

 > phone = Phonelib.parse('03-1234-5670', :jp)
=> #<Phonelib::Phone:0x00007fcd36e70eb8 @original="03-1234-5670", @extension="", @sanitized="0312345670", @original_s="03-1234-5670", @data={"JP"=>{:id=>"JP", :country_code=>"81", :international_prefix=>"010", :national_prefix=>"0", :mobile_number_portable_region=>"true", :national=>"312345670", :format=>{:pattern=>"(\\d)(\\d{4})(\\d{4})", :national_prefix_formatting_rule=>"$NP$FG", :leading_digits=>"[36]|4(?:2(?:0|9[02-69])|7(?:0[019]|1))", :format=>"$1-$2-$3"}, :valid=>[:fixed_line], :possible=>[:premium_rate, :toll_free, :personal_number, :uan, :fixed_line]}}, @national_number="312345670">
> phone.valid?
=> true

正しくない電話番号をパースしたときには以下の通りvalid?メソッドで判定できます。

> phone = Phonelib.parse('03-1234-567o', :jp)
=> #<Phonelib::Phone:0x00007fcd3c21a5a0 @original="03-1234-567o", @extension="", @sanitized="031234567", @original_s="03-1234-567o", @data={"JP"=>{:id=>"JP", :country_code=>"81", :international_prefix=>"010", :national_prefix=>"0", :mobile_number_portable_region=>"true", :national=>"31234567", :format=>{:pattern=>"(\\d+)(\\d{3})(\\d{4})", :format=>"$1 $2 $3"}, :valid=>[], :possible=>[:toll_free]}}, @national_number="31234567">
> phone.valid?
=> false

電話番号から対応する地理情報の取得

固定電話だと市外局番と市内局番により対応する地理情報を取得できます。東京都はちょっとエリアがざっくりしていますね。

日本の市外局番 - Wikipedia

Phonelib.parse('011-231-4111',:jp).geo_name => "Sapporo, Hokkaido" # 北海道
Phonelib.parse('017-722-1111',:jp).geo_name => "Aomori, Aomori"  # 青森県
Phonelib.parse('019-651-3111',:jp).geo_name => "Morioka, Iwate"  # 岩手県
Phonelib.parse('022-211-2111',:jp).geo_name => "Sendai, Miyagi"  # 宮城県
Phonelib.parse('018-860-1111',:jp).geo_name => "Akita, Akita"    # 秋田県
Phonelib.parse('023-630-2211',:jp).geo_name => "Yamagata, Yamagata"  # 山形県
Phonelib.parse('024-521-1111',:jp).geo_name => "Fukushima, Fukushima"    # 福島県
Phonelib.parse('029-301-1111',:jp).geo_name => "Mito, Ibaraki"   # 茨城県
Phonelib.parse('028-623-2323',:jp).geo_name => "Utsunomiya, Tochigi" # 栃木県
Phonelib.parse('027-223-1111',:jp).geo_name => "Maebashi, Gunma" # 群馬県
Phonelib.parse('048-824-2111',:jp).geo_name => "Urawa, Saitama"  # 埼玉県
Phonelib.parse('043-223-2110',:jp).geo_name => "Chiba, Chiba"    # 千葉県
Phonelib.parse('03-5321-1111',:jp).geo_name => "Tokyo"   # 東京都
Phonelib.parse('045-210-1111',:jp).geo_name => "Yokohama, Kanagawa"  # 神奈川県
Phonelib.parse('025-285-5511',:jp).geo_name => "Niigata, Niigata"    # 新潟県
Phonelib.parse('076-431-4111',:jp).geo_name => "Toyama, Toyama"  # 富山県
Phonelib.parse('076-225-1111',:jp).geo_name => "Kanazawa, Ishikawa"  # 石川県
Phonelib.parse('0776-21-1111',:jp).geo_name => "Fukui, Fukui"    # 福井県
Phonelib.parse('055-237-1111',:jp).geo_name => "Kofu, Yamanashi" # 山梨県
Phonelib.parse('026-232-0111',:jp).geo_name => "Nagano, Nagano"  # 長野県
Phonelib.parse('058-272-1111',:jp).geo_name => "Gifu, Gifu"  # 岐阜県
Phonelib.parse('054-221-2455',:jp).geo_name => "Shizuoka, Shizuoka"  # 静岡県
Phonelib.parse('052-961-2111',:jp).geo_name => "Nagoya, Aichi"   # 愛知県
Phonelib.parse('059-224-3070',:jp).geo_name => "Tsu, Mie"    # 三重県
Phonelib.parse('077-528-3993',:jp).geo_name => "Otsu, Shiga" # 滋賀県
Phonelib.parse('075-451-8111',:jp).geo_name => "Kyoto, Kyoto"    # 京都府
Phonelib.parse('06-6941-0351',:jp).geo_name => "Osaka, Osaka"    # 大阪府
Phonelib.parse('078-341-7711',:jp).geo_name => "Kobe, Hyogo" # 兵庫県
Phonelib.parse('0742-22-1101',:jp).geo_name => "Nara, Nara"  # 奈良県
Phonelib.parse('073-432-4111',:jp).geo_name => "Wakayama, Wakayama"  # 和歌山県
Phonelib.parse('0857-26-7111',:jp).geo_name => "Tottori, Tottori"    # 鳥取県
Phonelib.parse('0852-22-5111',:jp).geo_name => "Matsue, Shimane" # 島根県
Phonelib.parse('086-224-2111',:jp).geo_name => "Okayama, Okayama"    # 岡山県
Phonelib.parse('082-228-2111',:jp).geo_name => "Hiroshima, Hiroshima"    # 広島県
Phonelib.parse('083-922-3111',:jp).geo_name => "Yamaguchi, Yamaguchi"    # 山口県
Phonelib.parse('088-621-2500',:jp).geo_name => "Tokushima, Tokushima"    # 徳島県
Phonelib.parse('087-831-1111',:jp).geo_name => "Takamatsu, Kagawa"   # 香川県
Phonelib.parse('089-941-2111',:jp).geo_name => "Matsuyama, Ehime"    # 愛媛県
Phonelib.parse('088-823-1111',:jp).geo_name => "Kochi, Kochi"    # 高知県
Phonelib.parse('092-651-1111',:jp).geo_name => "Fukuoka, Fukuoka"    # 福岡県
Phonelib.parse('0952-24-2111',:jp).geo_name => "Saga, Saga"  # 佐賀県
Phonelib.parse('095-824-1111',:jp).geo_name => "Nagasaki, Nagasaki"  # 長崎県
Phonelib.parse('096-383-1111',:jp).geo_name => "Kumamoto, Kumamoto"  # 熊本県
Phonelib.parse('097-536-1111',:jp).geo_name => "Oita, Oita"  # 大分県
Phonelib.parse('0985-26-7111',:jp).geo_name => "Miyazaki, Miyazaki"  # 宮崎県
Phonelib.parse('099-286-2111',:jp).geo_name => "Kagoshima, Kagoshima"    # 鹿児島県
Phonelib.parse('098-866-2333',:jp).geo_name => "Naha, Okinawa"   # 沖縄県

ActiveRecordのValidatorとして利用

ActiveRecordでPhonelibをValidatorとして利用するときは以下のように利用します。

class Company < ApplicationRecord
  # phone_noという列を定義しているとします
  validates :phone_no, phone: {allow_blank: true, countries: [:jp]}
end

c = Company.first
c.phone_no = '031234567a'
c.valid? => false
c.errors.full_messages => ["電話番号は不正な値です"]

なお、検証対象の国が日本など固定の場合にはconfig/initializer/phonelib.rbに指定することで省略することができます。

$ touch config/initializers/phonelib.rb
$ echo 'Phonelib.default_country = "JP"' >>  config/initializers/phonelib.rb

その他設定を記載することもできますが、詳細はREADMEを参照してください。

daddyz/phonelib: Ruby gem for phone validation and formatting using google libphonenumber library data

まとめ

今回ざっと紹介した以外にもいろいろな機能があるのですが、Rubyで電話番号を扱う上ではこのライブラリが便利ではないでしょうか。