Правильные (Regular) выражения и класс Regex. Операторы над компонентами регулярных выражений, страница 6

Объясните число совпадений. Каждое совпадение состоит из ? групп, в каждой группе имеется по ? захвату. Ясно-ли вам, почему в совпадении две группы? Потому, что шаблон выражения содержит две группы:

¨  нулевую — все выражение (.)\1, то есть сдвоенный символ,

¨  первую — выражение (.), то есть произвольный символ.

Я думаю, что дело обстоит так. (Рассуждения песика Фафика). При поиске совпадений апгоритм последовательно продвигается по строке text и выбирает ее очередной символ. В соответствии с шаблоном он пристыковывает к нему еще один, такой же. Затем он проверяет, начиная с текущей позиции, нет-ли совпадения. Если есть, то оно обрабатывается в соответствии с нашим кодом. Попав на первую букву 'o' в слове Tool, алгоритм обнаруживае первое совпадение. Так как оно автоматически проверяется по обеим группам, то в коллекцию групп попадают две группы, имеющие по одному захвату. Попробуйте предсказать вывод, если заменить шаблон на: pattern = @"\s+(\w+)(.)\2";.

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

string[] groups = ex.GetGroupNames();

foreach (string group in groups)

Console.Write ("Group: " + group + ", ");

Console.WriteLine ("\n");

Тот же результат вы получите, если испытаете другой метод:

int[] groups = ex.GetGroupNumbers();

foreach (int group in groups)

Console.Write ("Group: " + group + ", ");

Console.WriteLine ("\n");

Компания Microsoft иллюстрирует логику поиска совпадений и образования групп на следующем примере. Запустите и объясните.

text = "One car red car blue car";

pattern = @"(\w+)\s+(car)";

Телефонные номера

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

pattern = @"[^\d]*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4})";

Он содержит 4 группы (0, 1, 2, 3). Отдельные части выражения имеют следующий смысл:

¨  [^\d]* — Возможны не цифры,

¨  (\d{3}) — Группа из трех цифр (ее номер 1),

¨  (\d{4}) — Группа из четырех цифр (ее номер 3),

Наш тест при испытании шаблона строкой "(812)103-0202" обнаружит одно совпадение. Значения групп: 0 — "(812)103-0202", 1 — "812", 2 — "103", 3 — "0202". Недостатком шаблона является то, что номер телефона, записанный в виде строки "(812)103-02-02" будет забракован. Скорректируйте шаблон, чтобы он стал пропускать строки в указанном формате.

Вопрос: Сколько групп содержит шаблон?

Пройдет ли испытание строка: text = @"Hello, ( 812 ) 103.02.02 is my phone number."?

Пройдет ли испытание строка:

text = "Затраты: 812 у.е. Приобретено: 103 CD-диска, 90 мышей, 90 ковриков";

Вывод. Ценность шаблона не в том, что он пропускает номера телефонов, а в том, что не пропускает глупости. Приведем, наконец, действительно полезный шаблон для номера телефона:

pattern = @"^\(?([1-9]\d{2})\)?\s?([1-9]\d{2})[-\s]?(\d{4})$";

Следующая таблица содержит расшифровку его компонентов. Заполните таблицу.

Подстрока

Смысл

^

\(?

(

[1-9]

\d{2}

)

\)?

\s?

([1-9]\d{2})

[-\s]?

(\d{4})

$

Этот шаблон значительно более строгий. То, что он пропустит, вряд-ли обозначает что-либо, кроме номера телефона. Шаблон также учитывает тот факт, что код города и вторая тройка цифр (телефонный узел, или exchange) не могут начинаться с нуля. Работая с базами данных, часто приходится вводить номера телефонов, поэтому следующая функция (или метод класса) может понадобиться в арсенале программиста. Заполните пропуск.

private bool IsPhoneValid (string phone)

{

return (new Regex (" ")) .IsMatch(phone);