Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can the order of elements in a list cause a bug in a for loop?

I'm playing with a simple script to escape certain HTML characters, and am encountering a bug which seems to be caused by the order of elements in my list escape_pairs. I'm not modifying the lists during a loop, so I can't think of any Python/programming principles I'm overlooking here.

escape_pairs = [(">", "&gt;"),("<","&lt;"),('"',"&quot;"),("&","&amp;")]

def escape_html(s):
    for (i,o) in escape_pairs:
        s = s.replace(i,o)
    return s

print escape_html(">")
print escape_html("<")
print escape_html('"')
print escape_html("&")

returns

&amp;gt;
&amp;lt;
&amp;quot;
&amp;

However when I switch the order of the elements in my escape_pairs list to the bug disappears

>>> escape_pairsMod = [("&","&amp;"),("<","&lt;"),('"',"&quot;"),(">", "&gt;")]

&gt;
&lt;
&quot;
&amp;
like image 573
dylankb Avatar asked Oct 20 '22 04:10

dylankb


1 Answers

Yes, in your first implementation, it can.

Lets take the case of > and the list -

escape_pairs = [(">", "&gt;"),("<","&lt;"),('"',"&quot;"),("&","&amp;")]

When iterating through escape_pairs , you first get > and replace it with &gt; . This causes the string to become '&gt; . Then you keep on iterating, and at the end you find ("&","&amp;") , and you replace the & in the string with &amp; , making the result the one you get right now.

When you change the order of the lists, you get the correct result. But still this is just because you first took into consideration & and only after that you took other in consideration.

You can use str.translate instead to translate the string coorectly , according to a dictionary. Example -

>>> escape_pairs = [(">", "&gt;"),("<","&lt;"),('"',"&quot;"),("&","&amp;")]
>>> escape_dict = dict(escape_pairs)
>>> t = str.maketrans(escape_dict)
>>> ">".translate(t)
'&gt;'
>>> "> & <".translate(t)
'&gt; &amp; &lt;'

But if what you want to do is HTML escape the string, then you should use the standard library - cgi -

>>> import cgi
>>> cgi.escape("< > &")
'&lt; &gt; &amp;'

Also, if you are using Python 3.2 + , you can use html.escape instead, Example -

>>> import html
>>> html.escape("< > &")
'&lt; &gt; &amp;'
like image 117
Anand S Kumar Avatar answered Oct 21 '22 21:10

Anand S Kumar