Non-capturing скоби в регулярните изрази на PHP

Скобите () изпълняват две функции - групиране на символи и функция на capturing група. А какво да правим, ако ни трябва да групираме, но да не capture-ваме в група? За решаване на този проблем са създадени специални non-capturing скоби (?: ) - те групират, но не capture-ват в група.

Пример

В следващия пример първите скоби са ни необходими за групиране, а вторите - за capturing група. Обаче, и едините, и другите скоби capture-ват данни в група:

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

В резултат в нашите capturing групи ще има следното:

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

Пример

Нека направим така, че първата двойка скоби само да групира, но да не capture-ва в група:

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

В резултат в първата capturing група ще бъде нашето число:

php<?php
  var_dump($res[1]); // ще изведе '123'
?>

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

Задание 1

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

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

Намерете всеки от такива поднизове и за всеки намерен подниз сложете в първата capturing група това, което стои преди разделителя, а във втората capturing група - това, което стои след разделителя.