MSLibrary. Захват и верификация телефонных номеров с помощью регулярных выражений, для IOS и не только… Часть 2

от автора

В первой части статьи разработчики библиотеки MSLibrary for iOS рассказали об особенностях структуры телефонных номеров с точки зрения международных стандартов, опубликованных в документе RFC 3966 , рассмотрели Международную структуру телефонных номеров, корпоративные WEB стандарты набора телефонного номера, их взаимодействие между собой и то, как ведут себя пользователи.
Как уже было сказано, захват и верификация это — разные задачи, но решаются они схожими методами, различающимися в основном применяемыми в них регулярными выражениями. Во второй части статьи речь пойдет собственно о регулярных выражениях.

Верификация телефонных номеров

Возможно несколько подходов к постановке задачи верификации или валидации строки телефонного номера.
1. выбрать один наиболее простой вариант написания валидного номера и сконструировать для него регулярное выражение
2. рассмотреть максимально большое множество валидных написаний телефонных номеров и сконструировать регулярное выражение под них

Оба подхода имеют право на существование, но каждый из них влечет за собой определенные последствия.
В первом случае либо пользователю придется вводить номер в том виде, в каком производится верификация, что часто приводит к ошибкам и, как следствие, к негативному отношению к приложению. Либо от разработчика потребуется создавать шаблон для ввода данных или дополнительный код, приводящий введенные данные к выбранному валидному виду.
Во втором случае можно обойтись без шаблона и дополнительного кода, ограничившись небольшой инструкцией типа «вводите телефонный номер без пробелов».

Рассмотрим оба варианта, но сначала общие соображения.

Валидация строки телефонного номера, чтобы он был адекватно обработан iOS, сводится к нескольким условиям:
1. общая структура номера должна соответствовать документу RFC 3966

telephone-uri = global-number-digits [extension]

рис. 1

2. телефонный номер должен всегда начинаться и заканчиваться с цифры

3. структура global-number-digits должна соответствовать документу RFC 3966 с учетом п.2 ( см. первую часть статьи )

	global-number-digits	= "+" * DIGIT *phonedigit DIGIT 

4. количество цифровых знаков в global-number-digits должно находиться в диапазоне 11-13 цифр (это условие следует из Международной структуры телефонных номеров)

5. структура необязательного элемента — добавочного номера [extension] должна отличаться от предложенной в документе RFC 3966

	extension		= (";" | *",") 1*(DIGIT *phonedigit DIGIT)

Подставив соответствующие значения в схему, изображенную на рис.1, получим более подробную структуру телефонного номера валидного для iOS:

telephone-uri = "+" DIGIT (9-11)*phonedigit DIGIT [(";" | *",") DIGIT *phonedigit DIGIT]

рис. 2

И только теперь, убедившись, в том, что полученная структура (рис. 2) удовлетворяет поставленной задаче и международным соглашениям, можно приступать к конструированию регулярных выражений.

Для наглядности начнем с регулярных выражений для каждой из частей структуры, изображенной на рис. 2.

DIGIT

	REGEX			[0-9] 	REGEX_OBJC_STRING	@"\\d"

phonedigit

	REGEX			[0-9]|[-\.\(\)] 	REGEX_OBJC_STRING	@"\\d|[-\\.\\(\\)]"

Приступим к конструированию регулярного выражения для первого варианта. Выберем одно, самое простое, написание валидного для iOS систем телефонного номера, например

 	+14089961010;1234 

Регулярное выражение, описывающее структуру этого телефонного номера, выглядит следующим образом:

	REGEX			^((?:\+?[0-9]{11,13})(?:(;|,+)[0-9]+)?)$

Разберем это выражение:

 	^(			# начало строки 	(?:			# начало блока global-number-digits 	\+?			# знак "+" (возможно использование не более одного раза) 	[0-9]			# сегмент DIGIT блока global-number-digits 	{11,13}			# указатель на то, что сегмент DIGIT возможен от 11 до 13 раз 	)			# окончание блока global-number-digits 	(?:			# начало блока extension 	(;|,+)			# сепаратор, указывающие на начало добавочного номера 	[0-9]+			# сегмент DIGIT блока extension 	)?			# окончание блока extension 	)$			# окончание строки 

Итак, для первого, из рассматриваемых вариантов, следующее регулярное выражение можно использовать для валидации телефонного номера перед его использованием в коде iOS приложения:

	REGEX_OBJC_STRING	@"^((?:\\+?\\d{11,13})(?:(;|,+)\\d+)?)$"

Для второго варианта, валидного для iOS систем, телефонного номера, полностью удовлетворяющего структуре, изображенной на рис. 2, регулярное выражение, выглядит следующим образом:

	REGEX			^((?:\+?[0-9]([-.\(\)]?[0-9]){10,12})(?:(;|,+)([0-9]([-.\(\)]?[0-9])?)+)?)$

Разберем это выражение:

 	^(			# начало строки 	(?:			# начало блока global-number-digits 	\+?			# знак "+" (возможно использование не более одного раза) 	[0-9]			# первый сегмент DIGIT блока global-number-digits 	(			# начало сегмента phonedigit блока global-number-digits 	[-.\(\)]?		# визуальный сепаратор (возможно использование не более одного раза в данном сегменте) 	[0-9]			# второй сегмент DIGIT блока global-number-digits 	)			# окончание сегмента phonedigit блока global-number-digits 	{10,12}			# указатель на то, что сегмент phonedigit возможен от 10 до 12 раз 	)			# окончание блока global-number-digits 	(?:			# начало блока extension 	(;|,+)			# сепаратор, указывающие на начало добавочного номера 	(			# начало цифровой части блока extension 	[0-9]			# первый сегмент DIGIT блока extension 	(			# начало сегмента phonedigit блока extension 	[-.\(\)]?		# визуальный сепаратор (возможно использование не более одного раза в данном сегменте) 	[0-9]			# второй сегмент DIGIT блока extension 	)?			# окончание сегмента phonedigit блока extension 	)+			# окончание цифровой части блока extension 	)?			# окончание блока extension 	)$			# окончание строки 

Итак, для второго, из рассматриваемых вариантов следующее регулярное выражение можно использовать для валидации телефонного номера перед его использованием в коде iOS приложения:

	REGEX_OBJC_STRING	@"^((?:\\+?\\d([-.\\(\\)]?\\d){10,12})(?:(;|,+)(\\d([-.\\(\\)]?\\d)?)+)?)$"

Захват телефонных номеров

Захват — это определение того, что трестируемый набор цифр и знаков может быть телефонным номером. При конструировании регулярного выражения для захвата телефонного номера следует учитывать, что в анализируемой строке:
1. должны содержаться все элементы, необходимые для успешной верификации телефонного номера в необходимой последовательности

2. могут содержаться инородные элементы

3. валидные сепараторы могут быть подменены на невалидными

На втором и третьем пунктах следует остановиться подробнее. Попробуем разобраться в весьма расплывчатых понятиях «инородные» и «невалидные» элементы.

В качестве визуальных сепараторов, кроме рассмотренных выше, при ручном наборе часто используют пробел (whitespace). Пробел может быть использован и как невалидный сепаратор и как инородный элемент, в случае, если он стоит перед или после сепаратора.
Для, обозначения начала добавочного номера, могут быть использованы следующие невалидные сепараторы:

	"x" | "ext" | ":" | "p" | "=" 

С учетом вышесказанного, регулярное выражение для phonedigit и сепаратора, обозначающего начало добавочного номера, примут следующий вид:
phonedigit

	REGEX			[0-9]|(\s?[-\.\(\)\s]\s?) 	REGEX_OBJC_STRING	@"[0-9]|(\\s?[-\\.\\(\\)\\s]\\s?)"

сепаратор добавочного номера

	REGEX			(x|ext|p|;|=|,+) 	REGEX_OBJC_STRING	@"(x|ext|p|;|=|,+)"

Регулярное выражение, удовлетворяющее поставленным условиям, выглядит следующим образом:

	REGEX			 ^(\s?(?:(\+?\s?[0-9]((\s?[-\.\(\)\s]\s?)?[0-9]){10,12}))(?:((x|ext|p|;|=|,+)(\s?[0-9]((\s?[-\.\(\)\s]\s?)?[0-9])?)+)?)$ 

Разберем это выражение:

 	^(			# начало строки 	\s?			# пробел, допустимый в начале строки 	(?:(			# начало блока global-number-digits 	\+?			# знак "+" (возможно использование не более одного раза) 	\s?			# пробел, допустимый после знака "+" 	[0-9]			# первый сегмент DIGIT блока global-number-digits 	(			# начало сегмента phonedigit блока global-number-digits 	(\s?[-\.\(\)\s]\s?)?	# визуальный сепаратор (возможно использование не более одного раза в данном сегменте) 	[0-9]			# второй сегмент DIGIT блока global-number-digits 	)			# окончание сегмента phonedigit блока global-number-digits 	{10,12}			# указатель на то, что сегмент phonedigit возможен от 10 до 12 раз 	))			# окончание блока global-number-digits 	(?:(			# начало блока extension 	(x|ext|p|;|=|,+)	# сепаратор, указывающие на начало добавочного номера 	(			# начало цифровой части блока extension 	\s?			# пробел, допустимый в начале цифровой части блока extension 	[0-9]			# первый сегмент DIGIT блока extension 	(			# начало сегмента phonedigit блока extension 	(\s?[-\.\(\)\s]\s?)?	# визуальный сепаратор (возможно использование не более одного раза в данном сегменте) 	[0-9]			# второй сегмент DIGIT блока extension 	)?			# окончание сегмента phonedigit блока extension 	)+			# окончание цифровой части блока extension 	)?			# окончание блока extension 	)$			# окончание строки 

Итак, для захвата телефонного номера, удовлетворяющего поставленным условиям, можно использовать следующее регулярное выражение:

	REGEX_OBJC_STRING	@"^(\\s?(?:(\\+?\\s?\\d((\\s?[-\\.\\(\\)\s]\\s?)?\\d){10,12}))(?:((x|ext|p|;|=|,+)(\\s?\\d((\\s?[-\\.\\(\\)\\s]\\s?)?\\d)?)+)?)$"

Для того, чтобы использовать захваченный таким образом телефонный номер, необходимо произвести его нормирование, то есть привести строку к валидному для использования в iOS виду. Описание технологии нормирования выходит за рамки тематики данной статьи. Можно сказать только, что в библиотеке MSLibrary for iOS эта задача решается применением одной единственной функции.

Подведем итоги

Задача верификации или валидации строки телефонного номера решается с помощью одного из следующих регулярный выражений:

	REGEX_OBJC_STRING	@"^((?:\\+?\\d{11,13})(?:(;|,+)\\d+)?)$"

	REGEX_OBJC_STRING	@"^((?:\\+?\\d([-.\\(\\)]?\\d){10,12})(?:(;|,+)(\\d([-.\\(\\)]?\\d)?)+)?)$"

Задача захвата строки, содержащей телефонный номер, может быть решена с помощью следующего регулярного выражения:

	REGEX_OBJC_STRING	@"^(\\s?(?:(\\+?\\s?\\d((\\s?[-\\.\\(\\)\s]\\s?)?\\d){10,12}))(?:((x|ext|p|;|=|,+)(\\s?\\d((\\s?[-\\.\\(\\)\\s]\\s?)?\\d)?)+)?)$"

Использовать полученные регулярные выражения при разработке iOS приложений можно с помощью методов класса NSRegularExpression .

В библиотеке MSLibrary for iOS для этого также имеются свои инструменты. К примеру, функция msfFRMreqMatchesInString

BOOL msfFRMreqMatchesInString(NSString *string, NSString *regularExpression, NSInteger reqNumberOfMatches) 

рис. 3

Эта функция принимает значение YES или NO, зависимости от того, удовлетворяет ли строка «string» регулярному выражению «regularExpression» определенное количество раз — «reqNumberOfMatches». Как видите вопрос решается всего в одну строку кода.
Кроме того в библиотеке имеется несколько десятков тщательно подобранных регулярных выражений «на всякие случаи жизни».


Надеемся, что материал был для вас полезен, команда MSLibrary for iOS

Захват и верификация телефонных номеров с помощью регулярных выражений, для iOS и не только… Часть 1

ссылка на оригинал статьи https://habrahabr.ru/post/278359/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *