So, what would be the best way
Everyone will have different criteria for "best". Here, for example is the most generic approach to wrapping your capture groups inside an arbitrary string. This is best for teaching you how to achieve such a result in a perfectly general way without necessarily being the best way to achieve the stated objective. :-)
use strict;
use warnings;
use Test::More tests => 1;
my $str = '/a/b/c/d';
my $re = qr#^/a/b/([^/]*)/([^\/]*)#;
my $want = "/a/b/\033[1;31mc\033[0m/\033[1;31md\033[0m";
my @caps = $str =~ $re;
my $out = '/a/b/' . join '/', map {"\033[1;31m$_\033[0m"} @caps;
is $out, $want, "Matched '$want'";