Несохраняющие скобки в регулярках PHP

Скобки () выполняют две функции - группировка символов и функцию кармана. А что делать, если нам нужно сгруппировать, но в карман не класть? Для решения такой проблемы придуманы специальные несохраняющие скобки (?: ) - они группируют, но не кладут в карман.

Пример

В следующем примере первые скобки нам нужны для группировки, а вторые - для кармана. Однако, и те, и другие скобки сохраняют данные в карман:

php<?php
  $str = 'abab123';
  $reg = '#(ab)+([1-9]+)#';
  preg_match_all($reg, $str, $res);
?>

В результате в наших карманах будет следующее:

php<?php
  var_dump($res[0]); // выведет 'abab123'
  var_dump($res[1]); // выведет 'ab'
  var_dump($res[2]); // выведет '123'
?>

Пример

Сделаем так, чтобы первая пара скобок только группировала, но не клала в карман:

php<?php
  $str = 'abab123';
  $reg = '#(?:ab)+([1-9]+)#';
  preg_match_all($reg, $str, $res);
?>

В результате в первом кармане будет наше число:

php<?php
  var_dump($res[1]); // выведет '123'
?>

Практические задачи

Задание 1

Даны подстроки, разделенные на две части произвольным количеством пар $@:

php<?php
  $str = 'aaa$@bbb aaa$@$@bbb aaa$@$@$@bbb';
?>

Найдите каждую из таких подстрок и для каждой найденной подстроки положите в первый карман то, что стоит до разделителя, а во второй карман - то, что стоит после разделителя.