試した方法は
sub tag_change {
   local($_) = $_[0];
   1 while s/(.*)(&lt;(img([!-:A-~\s\=]+))&gt;)/$1<img$4>/i;
   1 while s/(.*)(&lt;(font[\s\w\=\#\"\']+)\&gt;(.*)\&lt;\/font\&gt;)/$1<$3>$4<\/font>/i;
   1 while s/(.*)(&lt;(b)&gt;(.*)&lt;\/b&gt;)/$1<b>$4<\/b>/i;
}
というやり方です。
どれくらい遅くなったかは計ってないですが、許可するタグを増やしていくと
あれ、ちょっと遅いかなと思う程度です。
そこまで速度にこだわる訳ではないですが、どうせなら良いものを作りたいと思いましたので
質問させていただきました。