Проходим челлендж RegexPlay на 100%

в 11:33, , рубрики: regex, Регулярные выражения

Челлендж от Machine Learning Lab Университета Триеста (Италия) предлагает решить 12 задач причём уровень задач сильно варьируется — от супер-лёгкого до сложного.

Конечно, решений может быть больше одного и тест-кейсы в задаче покрывают не все варианты. Тем не менее если набрали 100% — то поздравляю! Тест пройден.

Спойлер: в некоторых задачах (особенно лёгких) подсказка практически и есть решение.

Задача 1 — найти цифры

Имеется текст содержащий цифры, требуется найти все цифры.

Сложность: супер-лёгко.

Подсказка

Нужно использовать символ цифры и квантификатор множественности.

Решение

d+

"[0-9]+" тоже верное решение.

Разбор решения

  • "d" или "[0-9]" — любой одиночный символ от 0 до 9.
  • "+" — допускается один или более символов.

Задача 2 — найти mac-адреса

Имеется текст содержащий mac-адреса, нужно их найти.

Сложность: легко.

Подсказка

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

Решение

w{2}:w{2}:w{2}:w{2}:w{2}:w{2}

"+" вместо "{2}" тоже является верным решением, хоть и не до конца точным.

Разбор решения

  • "w" — любой символ алфавита или любая цифра.
  • "{2}" — допускается только 2 символа.

Лучшее решение

Те, кто хорошо знаком с mac-адресом заметили что mac-адрес записывается в шестнадцатеричной системе исчисления. А в предыдущем решении использовался знак w означающий любой символ алфавита и все цифры. Согласен, наверное это излишне, но можно это учесть, заодно сократив регулярку.

([da-f]{2}:){5}[da-f]{2}

Разбор решения

  • "d" — любая одиночная цифра, "a-f" — диапазон от a до f. Итого мы имеем допустимый набор символов 0123456789abcdef — то есть шестнадцатеричный код Hex. "{2}" — любые 2 символа из этого набора символов.
  • "([da-f]{2}:)"{5} — допустимо повторение двух символов hex + двоеточие ровно 5 раз.
  • и в конце "[da-f]{2}" — любые 2 имвола из набора hex

Задача 3 — найти ftp-адреса

Имеется текст с ftp-адресами, требуется их найти.

Сложность: легко.

Подсказка

Нужно начать с ftp:// а затем перечислить допустимые символы в адресе, не забыв про квантификатор множественности.

Решение

ftp://[wd-_./]+

Разбор решения

  • "/" — обычное экранирование символа "/".
  • внутри квадратных скобок перечисление допустимых символов, а именно — любой символ алфавита или любая цифра, дефис, нижнее подчёркивание, точка или слэш (если в имени есть другие символы — их можно дописать).

Задача 4 — найти шаблон

Имеется какой то форматированный файл в котором нужно найти все строки соответствующие шаблону $любые символы$.

Сложность: легко.

Подсказка

Нужно использовать экранирование зарезервированного символа, символ любого символа, квантификаторы множественности и ленивый.

Решение

Банальная задача, но требует уже немного лучшего знания регулярок.

\$.+?\$

Разбор решения

  • "\$" — экранирование доллара.
  • ".+" — любое количество любых символов, "?" — убираем жадность.

Задача 5 — найти ip-адреса

Из текста найти ip-адреса.

Сложность: легко.

Подсказка

Очень похоже на вторую задачу.

Решение

d+.d+.d+.d+

Если вместо "+" вы написали "{1,3}" то вы молодец.

Разбор решения

  • "d" — любая одиночная цифра,
  • "+" — любое количество символов, "{1,3}" — жёсткое ограничение на количество символов (от 1 до 3).

Лучшее решение

ip-адрес это не просто цифры, а цифры от 0 до 255.

b((d|[1-9]d|1d{2}|2[0-4]d|25[0-5]).){3}(d|[1-9]d|1d{2}|2[0-4]d|25[0-5])b

Разбор решения

Что бы определить диапазон от 0 до 255 придётся немного постараться:

  • "d" — число от 0 до 9
  • "[1-9]d" — число от 10 до 99
  • "1d{2}" — число от 100 до 199
  • "2[0-4]d" — число от 200 до 249
  • "25[0-5]" — чилсо от 250 до 255

Далее разрешаем повторение шаблона цифры от 0 до 255 ровно 3 раза:

  • "(d|[1-9]d|1d{2}|2[0-4]d|25[0-5]).){3}" — внутри точка, потому что она тоже повторяется 3 раза и в конец тот же диапазон чисел, но без точки.
  • в конец и начало добавляем символ границы слова "b" — нужен для того что бы убрать из вхождения например такой текст "1172.30.42.109" (согласен, маловероятно и наверное излишне).

Задача 6 — анкор

Из html-документа вытащить тег href.

Сложность: средне.

Подсказка

Следует использовать "любой символ кроме" и "или" для каждой скобки.

Решение

href=("[^"]+"|'[^']+')

Разбор решения

  • " — начинаем поиск с двойной кавычки.
  • "[^"]+" — далее совершенно любой символ кроме двойной кавычки.
  • Заканчиваем двойной кавычкой.

Всё это помещаем в круглые скобки, дописываем знак или — "|" и повторяем тоже самое для одинарных кавычек.

Задача 7 — ссылки

В произвольном тексте найти все ссылки. Задача усложняется тем что не достаточно просто найти ссылку, нужно выкинуть с конца не допустимые символы.

Сложность: сложно.

Подсказка

Нужно начинать с http, использовать "любой символ кроме" и закончить поиск символом который допустим.

Решение

http://([^>s]+)[w/]

В задаче нет ссылок https, но можно это учесть добавив "s?" после http.

Разбор решения

  • "[^>s]+" ищем любые символы кроме символа ">" и символа проблема. По сути дела читать можно так "идём до тех пор пока не увидим один из этих символов".
  • "[w/]" — это ограничитель который разрешает заканчивать ссылку только латинским символом или слэшем.

И по итогу — начинаем с http://, далее совершенно любой символ кроме символов "<" или пробела, но в конце обязателен символ латинского алфавита или слэш.

  • дополнительные "s?" в "https?" просто разрешают как "http://" так и "https://".

Задача 8 — заголовки

В HTML заголовком считается любой тег h + цифра.

Сложность: средне.

Подсказка

Начните с h + цифра + любой символ или его отсутствие.

Решение

Довольно просто:

<hd.*>.*</hd.*>

Разбор решения

  • "hd" — здесь мы говорим что после символа обязательно должна идти "d" цифра.
  • А далее ".*" может идти любое количество любых символов или может не идти ничего.

Лучшее решение

После h идёт цифра, причем в спецификации html указано что допустимыми являются цифры от 1 до 6, а сам тег не может быть закрыт ничем кроме треугольных скобок. Следовательно такое решение будет более точным:

<h[1-6][^>]*>.+?</h[1-6]>

Правда тут есть ошибка позволяющая открыть тег одной цифрой, а закрыть другой. И поэтому ещё более точным решением будет использовать ссылки: "<h([1-6])[^>]*>.+?</h1>". Это не говоря о том что в тесте не учтен регистр.

Разбор решения

  • "h[1-6]" — здесь мы говорим что после "h" обязательно должна идти цифра от 1 до 6.
  • "[^>]*" — дальше могут идти совершенно любые символы кроме ">", а могу и не идти.

Отдельно про дополнение:

  • Обёртывая выражение "(h[1-6])" в скобки мы создаём группу под номером 1.
  • Далее используя ссылку на первую группу "1" мы говорим о том что хотим видеть в конце тот же самый, h с той же самой цифрой, что и в начале.

Задача 9 — телефоны

В произвольном тексте найти в все телефоны в разных форматах.

Сложность: сложно.

Подсказка

Необходимо использовать знак наличия символа или его отсутствия, квантификатор ограничения количества цифр, конструкцию набора символов. Возможна конструкция или.

Решение

(?d{3}[). /-]{1,2}d{3}[-.]d{4}

Работать будет, но допускает два символа после первых трех цифр — хорошо если это закрывающая скобка и пробел после неё, но плохо если два дефиса. Поэтому есть чуть более точное решение: "(?d{3}() ?|[./-])d{3}[-.]d{4}"

Разбор решения

  • "(?" — указываем на возможность наличия символа "(" или его отсутствия, экранируем т. к. это зарезервированный символ.
  • "d{3}" — цифры с ограничением только 3.
  • Далее возможны символы "[). /-]{1,2}" — слэш, закрывающая круглая скобка, точка, пробел, обратный слэш и дефис. {1,2} — говорит о том что этих символов может быть 1 или 2. Например закрывающая скобка и пробел после неё.
  • Далее обязательно "[-.]" — дефис или точка.
  • И "d{4}" — четыре цифры в конце.

Задача 10 — авторы

Есть некий паттерн содержащий элементы, найти всех авторов из поля author.

Сложность: очень сложно.

Подсказка

Необходимо опираться на тот факт что все имена авторов начинаются с большой буквы и написаны по шаблону.

Решение

[A-Z][A-Za-z-']+, [A-Z]({\"w})?[A-za-z-']*( [A-Z][A-Za-z-']*)?

Это решение верно, но имеет минус. Мы обошли "{"u}" костылем "({"w})?" и в принципе это работоспособно если так же засунуть этот костыль в другие части имен авторов.

В любом случае если вы смогли хоть как то решить эту задачу, это очень круто!

Разбор решения

  • "[A-Z][A-Za-z-']+" — Ищем слово которое обязательно начинается с большой буквы, затем содержит любой символ алфавита, дефис или апостроф.
  • Далее всё ровно тоже самое что и чуть выше, но здесь между мы имеем "({"w})?" — это просто костыль позволяющий обойти экранирование. Означает что кусок "{"u}" может как присутствовать, так и отсутствовать.
  • И далее опять ровно тоже самое что и в первом случае "( [A-Z][A-Za-z-']*)?", замет исключением что это выражение обвёрнуто в группу и стоит знак "?" означающий не обязательность этого условия.

P.S перечисление [A-Za-z] здесь вынужденная мера, потому что в тесте отсутствуют модификаторы.

Лучшее решение

Есть более компактное и простое решение позволяющее отказаться от костыля выше:

[A-Z]S+, [A-Z]S*( [A-Z][S]*)?b

Разбор решения

  • "[A-Z]S+, " — сначала, обязательно, заглавная буква "[A-Z]", затем любое количество не пробельных символов "S+" до точки с запятой ", ".
  • Далее почти тоже самое "[A-Z]S*" — начало обязательно с заглавной буквы, а потом любой не пробельный символ до границы слова "b".
  • "( [A-Z][S]*)?" — а между ними такая же, но не обязательная группа для отчества.

Задача 11 — содержимое заголовка

Точно так же как в задаче 8, но нужно найти не сами заголовки, а их содержимое.

Сложность: сложно.

Подсказка

Задача идентична 8 задаче. Это не сложно если знать про заглядывание назад и вперед.

Решение

(?<=<h[^>]+>).+?(?=</hd>)

Плюс можно учесть все замечания к решению 8 задаче: "(?<=<h([1-6])[^>]*>).+?(?=</h1>)"

Разбор решения

  • "(?<=<h[^>]+>)" — заглядывание назад внутри которого должен быть тег h.
  • "(?=</hd>)" — заглядывание вперед внутри которого должен быть закрывающий тег h.

Задача 12 — список авторов

Задача похожа на 10 задачу, но на мой взгляд проще.

Сложность: сложно.

Подсказка

Все основные принципы из 10 задачи, но нужно учесть начало строки.

Решение

Имеет несколько решений, например такое:

(?<=^d+. )[A-Z][w]+, [A-Z][w.]+

Разбор решения

  • "(?<=^d+. )" — заглядывание назад где обязательно с новой строки должно быть любое количество цифр до точки с пробелом.
  • "[A-Z][w]+, " — далее любое слово с заглавной буквы до точки с запятой и ещё раз тоже самое "[A-Z][w.]+".

Или по-проще, такое:

(?<=^d+. )[^,]+,[^,:]+

Разбор решения

  • "(?<=^d+. )" — заглядывание назад где обязательно с новой строки должно быть любое количество цифр до точки с пробелом.
  • "[^,]+," — любое количество любых символов до запятой + запятая.
  • "[^,:]+" — любое количество любых символов до запятой или двоеточия.

Автор: Алёхин Максим

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js