in reply to while loop w/match is hanging

Don't do that. It doesn't work, because the substitution resets the internal position pointer used with //g, so you'll always restart from the beginning.  (And even if it didn't, it still likely wouldn't work, if you modify the string such that the remembered start position for the next match is no longer correct... — you could in theory adjust it by assigning to pos($str) = ..., but why make things more complex than they need to be?)

Simply do a global substitution without prior matching, and put the computations in a separate sub. Something like this:

sub subst_str { my $match = shift; my $b = ... return "$match<tag3>$b</endtag3>"; } .. $str =~ s/(<tag1[^>]*>\s*<tag2>\s*)<tag3>[^<]*<\/endtag3>/subst_str($1 +)/gsie; # note the /e