my @tokens = / \\. # any backslashed character | \[ .*? \] # bracketed string (the one with magical powers) | [^\\\[\]]+ # any sequence of non-specials | . # catch-all (to inchworm past broken constructs like mismatched brackets or backslash at end of string) /xgs; for (@tokens) { if (/^[(.*)\]$/s) { # it's special $_ = process($1); # replace with its expansion } elsif (/^\\(.)/s) { # it's escaped $_ = $1; } } my $result = join "", @tokens; # if that's what you want