@@ -2425,19 +2425,33 @@ def _encode_email_address(self, addr: str) -> str:
24252425
24262426 def _unescape_special_chars (self , text : str ) -> str :
24272427 # Swap back in all the special characters we've hidden.
2428- hashmap = tuple (self ._escape_table .items ()) + tuple (self ._code_table .items ())
2428+ if 'md5-' not in text :
2429+ return text
2430+ # Build the hash -> original mapping directly, without intermediate tuples.
24292431 # html_blocks table is in format {hash: item} compared to usual {item: hash}
2430- hashmap += tuple (tuple (reversed (i )) for i in self .html_blocks .items ())
2431- replacements = {}
2432- for ch , hash in hashmap :
2432+ replacements : dict [str , str ] = {}
2433+ for ch , hash in self ._escape_table .items ():
24332434 replacements .setdefault (hash , ch )
2434- while True :
2435- orig_text = text
2436- # Scan once per nesting level instead of once for every stored hash.
2437- text = re .sub (r'md5-[0-9a-f]{32}' ,
2438- lambda match : replacements .get (match [0 ], match [0 ]), text )
2439- if text == orig_text :
2440- break
2435+ for ch , hash in self ._code_table .items ():
2436+ replacements .setdefault (hash , ch )
2437+ for hash , item in self .html_blocks .items ():
2438+ replacements .setdefault (hash , item )
2439+
2440+ def _sub (match : re .Match ) -> str :
2441+ nonlocal replaced
2442+ val = replacements .get (match [0 ])
2443+ if val is None :
2444+ return match [0 ]
2445+ replaced = True
2446+ return val
2447+
2448+ # Scan once per nesting level instead of once for every stored hash.
2449+ # Stop when a pass makes no replacement, rather than comparing the
2450+ # whole text against the previous pass.
2451+ replaced = True
2452+ while replaced :
2453+ replaced = False
2454+ text = re .sub (r'md5-[0-9a-f]{32}' , _sub , text )
24412455 return text
24422456
24432457 def _outdent (self , text : str ) -> str :
0 commit comments