Форматирование номера телефона (Swift)

Простая, но полезная с точки зрения UX штука - автоматическое форматирование телефонного номера в более читаемый формат. Задача простая: форматирование (в живом режиме) номера телефона из формата "XXXXXXXXXXX" в более красивый "+X (XXX) XXX-XXX".

/// Format phone number
/// Usage:
///
///     print(formatPhoneNumber(number: “12345678901”)) // +1 (234) 567-8901
private func formatPhoneNumber(number: String) -> String {
    let cleanPhoneNumber = number.components(separatedBy: CharacterSet.decimalDigits.inverted).joined()
    let mask = “+X (XXX) XXX-XXXX”

    var result = “”
    var index = cleanPhoneNumber.startIndex
    for ch in mask where index < cleanPhoneNumber.endIndex {
        if ch == “X” {
            result.append(cleanPhoneNumber[index])
            index = cleanPhoneNumber.index(after: index)
        } else {
            result.append(ch)
        }
    }
    return result
}

Этот метод можно использовать в textField. В контроллере не забываем делегировать textField, и в UITextFieldDelegate оставим такой метод:

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        guard let text = textField.text else { return false }
        let newString = (text as NSString).replacingCharacters(in: range, with: string)
        textField.text = formatPhoneNumber(number: newString)
        return false
}

Как это работает:

  • cleanPhoneNumber - переводит входной number в числовой формат (при попытке ввести буквы, к примеру)
  • mask - маска, она будет разной для разных стран

Если же необходимо получать номер телефона в более удобном, например, для базы данных, формате "XXXXXXXXXXX" (после редактирования в textField), можно использовать следующий метод:

/// Get unformatted phone number
/// Usage:
///
///     print(removeNumberFormat(number: “+1 (234) 567-8901”)) // 12345678901
private func removeNumberFormat(number: String) -> String {
    let digits = CharacterSet.decimalDigits
    var text = “”
    for char in number.unicodeScalars {
        if digits.contains(char) {
            text.append(char.description)
        }
    }
    return text
}

May 27, 2020