Paréntesis no capturadores en expresiones regulares de PHP

Los paréntesis () realizan dos funciones: agrupar caracteres y la función de captura. Pero, ¿qué hacemos si necesitamos agrupar, pero sin capturar? Para resolver este problema se crearon los paréntesis no capturadores (?: ) - agrupan, pero no capturan.

Ejemplo

En el siguiente ejemplo, los primeros paréntesis los necesitamos para agrupar, y los segundos - para capturar. Sin embargo, ambos tipos de paréntesis guardan datos en la captura:

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

Como resultado, en nuestras capturas tendremos lo siguiente:

php<?php
  var_dump($res[0]); // mostrará 'abab123'
  var_dump($res[1]); // mostrará 'ab'
  var_dump($res[2]); // mostrará '123'
?>

Ejemplo

Hagamos que el primer par de paréntesis solo agrupe, pero no capture:

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

Como resultado, en la primera captura estará nuestro número:

php<?php
  var_dump($res[1]); // mostrará '123'
?>

Tareas prácticas

Задание 1

Tenemos subcadenas, divididas en dos partes por una cantidad arbitraria de pares $@:

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

Encuentra cada una de estas subcadenas y para cada subcadena encontrada, guarda en la primera captura lo que está antes del separador, y en la segunda captura - lo que está después del separador.