Destructive tokenization via s/// can get expensive on large strings. An alternative that you might find worth checking out is to use m//gc (the /c "continues" a failing match) along with \G, which anchors to the position of the last succeeding match. See
perlop for an example.