はじめに
電話番号のバリデーションをするために電話番号を正規表現で表してみた。
正規表現については下記を参考にしてください。
初心者歓迎!手と目で覚える正規表現入門・その1「さまざまな形式の電話番号を検索しよう」
Ruby | Rubular で ruby の正規表現を検証しながら作成 #ruby #正規表現
Rubular(正規表現を検証しながら確認できます)
電話番号の前提条件
電話番号には様々な組み合わせ(桁数・ハイフン・括弧)があるが今回は下記を前提として表現する
・固定電話
・全部で10桁
・頭が0
・末尾は4桁
・ハイフンや括弧が入る可能性がある(なくても良い)
・携帯電話
・全部で11桁
・1,3桁目は0
・2桁目は5-9
・ハイフンや括弧が入る可能性がある(なくても良い)
これらを満たす電話番号のパターンは大きく分けて下記ようになる。(0は固定でxには任意の数字が入る)
・固定電話(10桁)
0x-xxxx-xxxx
0xx-xxx-xxxx
0xxx-xx-xxxx
0xxxx-x-xxxx
・携帯電話(11桁)
050-xxxx-xxxx
060-xxxx-xxxx
070-xxxx-xxxx
080-xxxx-xxxx
090-xxxx-xxxx
正規表現で表す(コピペでOK!!)
固定電話:\A0(\d{1}[-(]?\d{4}|\d{2}[-(]?\d{3}|\d{3}[-(]?\d{2}|\d{4}[-(]?\d{1})[-)]?\d{4}\z
携帯電話:\A0[5789]0[-]?\d{4}[-]?\d{4}\z
正規表現の解説
\A: 頭文字を表す
\d{n}: n桁の数字
[-(]?: "-"もしくは"("が入る (どちらもない場合もある)
|: or
\z: 最後の文字
読みやすくするために、下記のように区切ってみた。
(\d{1}[-(]?\d{4}|\d{2}[-(]?\d{3}|\d{3}[-(]?\d{2}|\d{4}[-(]?\d{1}) が長くてわかりにくくしていので "|"で改行した。
Rspecでのバリデーションとテスト
ここまでを考慮して電話番号のバリデーションとテストを書いてみた。
class User < ApplicationRecord
VALID_PHONE_NUMBER_REGEX = /\A0(\d{1}[-(]?\d{4}|\d{2}[-(]?\d{3}|\d{3}[-(]?\d{2}|\d{4}[-(]?\d{1})[-)]?\d{4}\z|\A0[5789]0[-]?\d{4}[-]?\d{4}\z/
validates :phone_number, presence: true, format: { with: VALID_PHONE_NUMBER_REGEX }
end
RSpec.describe User, type: :model do
before do
stub_const('VALID_PHONE_NUMBER_REGEX', \A0(\d{1}[-(]?\d{4}|\d{2}[-(]?\d{3}|\d{3}[-(]?\d{2}|\d{4}[-(]?\d{1})[-)]?\d{4}\z|\A0[5789]0[-]?\d{4}[-]?\d{4}\z)
end
context 'フォーマット' do
let(:user) { FactoryBot.create(:user) } # 別ファイルでUserのFactoryBotを作成しています。
it 'phone_numberのフォーマットが適切であること' do
expect(user.phone_number).to match(VALID_PHONE_NUMBER_REGEX)
end
end
end
@jnchitoさんに頂いたコメントを参考に下記を追加しました。(2020/6/22)
FactoryBot.define do
factory :user do
phone_number { "0#{rand(0..9)}0#{rand(1_000_000..99_999_999)}" }
# 1,3桁目が0, 全部で10-11桁の電話番号を生成
end
end