in reply to substitution on

You could do something like
while (s/((^|\>)[^\<]*?)\>/$1\&gt\;/g) { 1; }
Explained:
Look for the begin of the string or any closing > in place. From here, grab everything which is no opening < until you find the next closing >. Return the grabbed thing but replace the unmatched > by &gt;.
Do this in a while loop, because the first run may not catch all unmatched >'s until no new places are found.

The only 100% working solution would be using an XML/HTML parser. The sample above will mix up HTML-code like <a name=">here">

edit: Sorry, I just saw that my solution is working on the wrong side.

edit2: Here is the correct solution:

while (s/\<([^\>]*?(\<|$))/\&lt\;$1/g) { 1; }
Explained:
Every < which has no > (^\&gt; - match everything but >, *? = match 0 to as few as possible chars) until the earliest next < or and end-of-string is replaced.
Has been tested using the string
<<html><x<y</html><

Notice:
  • The same thing (using a XML/HTML parser for best results) is also true for this one.
  • Remember using /s if you're processing a multiline string