I'm trying to implement a pure Ruby phone number validator for the UK's number. There are a lot of topics related to phone validation but most of them use regex which I want to avoid (mainly because it's unreadable). I'm aware of phone_validator_gem but frankly I don't want to use any additional gems.
Let's make these assumptions:
- any perfix format allowed ( 447..., 447..., 07...)
- UK phone numbers are 11 digits long when in the 07... format and always have 7 after the prefix (whether it's 44, 44 or 0)
The implemented module should do:
- removes any spaces from number
- check it is valid (raises an error if not)
- outputs it in the 447... format
E.g. I call format with 071234 56789
as the input, it should return 447123456789
. If I call it with 063434, it should raise an error.
I've no idea is there any way to avoid regex? What I did so far is just simple removing whitespaces and check if it's 11 digits.long, my module below:
module Uk
VALID_PREFIX = ' 447'
def self.format(number)
clear_format = number.delete(' ')
return clear_format if clear_format.delete('^0-9').length == 11 && clear_format[0, 4].includes?(VALID_PREFIX)
end
end
CodePudding user response:
If you want to avoid gems and regexes, you're doing Rails in hard mode. I would strongly suggest you devote some time to getting comfortable with both.
Parsing phone numbers is always more complicated than you think. For example, your assumption that "UK phone numbers are 11 digits long when in the 07... format and always have 7 after the prefix (whether it's 44, 44 or 0)" is not correct. 07 is just a really common prefix.
It's best to leave it as someone else's problem, so if there's a gem use it. For example, uk-phone-number-formatter
seems to do exactly what you want and it is tiny.
Let's say we do this without regexes and without gems and assume 07 is the only prefix. First, separate the problem into two steps.
- Normalization
- Validation
Normalization is reformatting the phone number so that equivalent phone numbers look the same. Validation is validating its a phone number. Validation is much easier if the data has already been normalized.
That means stripping everything that isn't a digit, fixing the prefx, and adding the
at the front.
Stripping everything that isn't a digit is easy with gsub
: phone.gsub!(/\D /)
. Or the non-regex delete
: phone.delete('^0-9')
.
Now with non-numbers out of the way, we just want to change "07" into "447".
Finally, add the
.
def normalize(phone)
# Strip non-digits.
normalized = phone.delete('^0-9')
# Replace 07x with 447x
if normalized[0..1] == "07"
normalized[0] = "44"
end
# Add the plus.
return " #{normalized}"
end
Now that it's normalized, validation is easy.
# We assume the phone number is validated.
def phone_is_uk_format(phone)
errors.add(:phone, :missing_prefx, message: "Missing 447 prefix")
if normalized[0..3] != " 447"
# 12 because of the leading
errors.add(:phone, :wrong_length, message: "A phone number is 11 digits")
if normalized.length != 12
end
And integrating it with a model...
class Person < ApplicationRecord
validate :phone_is_uk_format
# Normalize the phone number when it is set.
def phone=(number)
super(normalize_uk_phone(number))
end
private def phone_is_uk_format
# Validating presence is different.
return if phone.blank?
errors.add(:phone, :missing_prefx, message: "Missing 447 prefix")
if phone[0..3] != " 447"
# 12 because of the leading
errors.add(:phone, :wrong_length, message: "A phone number is 11 digits")
if phone.length != 12
end
private def normalize_uk_phone(phone)
# Strip non-digits.
normalized = phone.delete('^0-9')
# Replace 07x with 447x
if normalized[0..1] == "07"
normalized[0] = "44"
end
# Add the plus.
return " #{normalized}"
end
end