Skip to content

Instantly share code, notes, and snippets.

@subdan
Created October 29, 2020 06:27
Show Gist options
  • Save subdan/06d076e90de214226de8dd3162bd7c31 to your computer and use it in GitHub Desktop.
Save subdan/06d076e90de214226de8dd3162bd7c31 to your computer and use it in GitHub Desktop.
Phone number formatter
import Cocoa
extension String {
func charAt(at: Int) -> Character {
let charIndex = index(startIndex, offsetBy: at)
return self[charIndex]
}
}
protocol PhoneNumberFormattable {
/// Код страны. Например: "7", "1" или "373"
var countryCode: String { get }
/// Кол-во цифр в номере телефона, исключая код страны
var numberCount: Int { get }
/// Маска для форматирования номера телефона исключая код страны. Например "### ###-##-##"
var mask: String { get }
/// Форматирует номер телефона
func format(rawNumber: String) -> String?
}
struct RussiaPhoneFormatter: PhoneNumberFormattable {
let countryCode = "7"
var numberCount: Int = 10
let mask: String = "### ###-##-##"
}
struct BelarusPhoneFormatter: PhoneNumberFormattable {
let countryCode = "375"
var numberCount: Int = 9
let mask: String = "## ###-##-##"
}
struct MoldovaPhoneFormatter: PhoneNumberFormattable {
let countryCode = "373"
var numberCount: Int = 8
let mask: String = "# ###-##-##"
}
struct KyrgyzstanPhoneFormatter: PhoneNumberFormattable {
let countryCode = "996"
var numberCount: Int = 9
let mask: String = "## ###-##-##"
}
extension PhoneNumberFormattable {
var countryCodeCount: Int { countryCode.count }
var totalCount: Int { numberCount + countryCodeCount }
func format(rawNumber: String) -> String? {
let rawNumber = rawNumber.filter { $0.isNumber }
guard rawNumber.count == totalCount else { return nil }
guard rawNumber.prefix(countryCodeCount) == countryCode else { return nil }
// numbers without country code
let numbers = String(rawNumber.dropFirst(countryCodeCount))
guard numbers.count == numberCount else { return nil }
var index = 0
var result = ""
mask.forEach { element in
if element == "#" {
result.append(numbers.charAt(at: index))
index += 1
} else {
result.append(element)
}
}
return "+\(countryCode) \(result)"
}
}
func formatPhoneNumber(_ string: String) -> String? {
let formatters: [PhoneNumberFormattable] = [
RussiaPhoneFormatter(),
BelarusPhoneFormatter(),
MoldovaPhoneFormatter(),
KyrgyzstanPhoneFormatter()
]
for formatter in formatters {
if let phone = formatter.format(rawNumber: string) {
return phone
}
}
return nil
}
print(formatPhoneNumber("71234567890") == "+7 123 456-78-90") // true
print(formatPhoneNumber("+996 12 345-67-89") == "+996 12 345-67-89") // true
print(formatPhoneNumber("+996123456789") == "+996 12 345-67-89") // true
print(formatPhoneNumber("37399999999") == "+373 9 999-99-99") // true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment