SQL HowTo: «чистые» регулярки (Advent of Code 2024, Day 3: Mull It Over)

от автора

В этой челлендж-серии статей попробуем использовать PostgreSQL как среду для решения задач Advent of Code 2024.

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

В этой части будет очень простой код, с чуть-чуть сложным регулярным выражением.


Оригинальная постановка задачи и ее перевод:

Advent of Code 2024, Day 3: Mull It Over

— День 3: Обдумайте это —

«У нас проблемы с компьютерами, так что я понятия не имею, есть ли у нас на складе главные историки ! Но вы можете проверить склад», — говорит слегка взволнованный владелец магазина по прокату санок North Pole Toboggan . Историки отправляются на поиски.

Хозяин магазина поворачивается к вам. «Есть ли шанс, что вы понимаете, почему у наших компьютеров снова возникли неполадки?»

Компьютер, похоже, пытается запустить программу, но его память (ваши входные данные для головоломки) повреждена . Все инструкции перепутаны!

Похоже, что цель программы — просто умножить несколько чисел. Она делает это с помощью инструкций типа mul(X,Y), где Xи Y— это 1-3-значные числа. Например, mul(44,46)умножает 44на , 46чтобы получить результат 2024. Аналогично, mul(123,4)умножает 123на 4.

Однако, поскольку память программы была повреждена, есть также много недопустимых символов, которые следует игнорировать, даже если они выглядят как часть инструкции mul. Последовательности вроде mul(4*mul(6,9!?(12,34), или mul ( 2 , 4 ) ничего не делают.

Например, рассмотрим следующий фрагмент поврежденной памяти:

xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))

Только четыре выделенных раздела являются реальными mulинструкциями. Сложение результатов каждой инструкции дает 1612*4 + 5*5 + 11*8 + 8*5).

Просканируйте поврежденную память на наличие неповрежденных mulинструкций. Что получится, если сложить все результаты умножений?

— Часть вторая —

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

Вам придется выполнить две новые инструкции:

  • Инструкция do() позволяет выполнять будущие инструкции mul

  • Инструкция don't() отключает будущие инструкции mul

В начале программы mulинструкции включены.

Например:

xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))

Эта поврежденная память похожа на пример из предыдущего, но на этот раз инструкции mul(5,5)и mul(11,8) отключены , потому что перед ними есть инструкция don't(). Другие инструкции функционируют нормально, включая ту, что в конце, которая снова включается инструкцией do().

На этот раз сумма результатов равна 482*4 + 8*5).

Обработайте новые инструкции: что получится, если сложить все результаты только включенных умножений?

Часть 1

  1. Поскольку на входе у нас «битая» строка, ограничим ее не апострофами, как обычно, а формой $token$..$token$.

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

  3. Просуммируем произведения — и все!

SELECT   sum(exp[1]::numeric * exp[2]::numeric) -- суммируем значения FROM   regexp_matches( $source$xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))$source$   , 'mul\((\d{1,3}),(\d{1,3})\)' -- скобки экранируем, числа 1..3-значые   , 'g'   ) exp;

Часть 2

  1. Фактически, надо убрать из исходной строки все части от don't() до do(). regexp_replace отлично подойдет для этого.

  2. Главное, не забыть два момента: заменять надо на непустую строку, чтобы не «склеились» части до/после, и не забыть убрать «хвост» после последнего don't().

SELECT   sum(exp[1]::numeric * exp[2]::numeric) FROM   regexp_matches(     regexp_replace(       $source$xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))$source$     , 'don''t\(\).*?(?:do\(\)|$)' -- "выстригаем" все блоки don't-do или don't-конец     , '_' -- непустая строка     , 'g' -- по всей строке     )   , 'mul\((\d{1,3}),(\d{1,3})\)'   , 'g'   ) exp;


ссылка на оригинал статьи https://habr.com/ru/articles/869004/


Комментарии

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

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