Come annullare la valutazione di una stringa Unicode codificata in Python?
-
08-07-2019 - |
Domanda
Ho una stringa unicode come " Tanim " che è codificato come "Tan% u0131m" in qualche modo. Come posso riconvertire questa stringa codificata in unicode originale. Apparentemente urllib.unquote non supporta unicode.
Soluzione
% uXXXX è un schema di codifica non standard che è stato rifiutato dal w3c, nonostante il fatto che un'implementazione continui a sopravvivere nella terra di JavaScript.
La tecnica più comune sembra essere quella di UTF-8 codificare la stringa e quindi% sfuggire ai byte risultanti usando% XX. Questo schema è supportato da urllib.unquote:
>>> urllib2.unquote("%0a")
'\n'
Sfortunatamente, se davvero hai bisogno di supportare% uXXXX, probabilmente dovrai girare il tuo decodificatore. Altrimenti, è probabile che sia molto più preferibile semplicemente codificare UTF-8 sul proprio unicode e quindi% sfuggire ai byte risultanti.
Un esempio più completo:
>>> u"Tanım"
u'Tan\u0131m'
>>> url = urllib.quote(u"Tanım".encode('utf8'))
>>> urllib.unquote(url).decode('utf8')
u'Tan\u0131m'
Altri suggerimenti
def unquote(text):
def unicode_unquoter(match):
return unichr(int(match.group(1),16))
return re.sub(r'%u([0-9a-fA-F]{4})',unicode_unquoter,text)
Questo lo farà se devi assolutamente avere questo (sono davvero d'accordo con le grida di "non standard"):
from urllib import unquote
def unquote_u(source):
result = unquote(source)
if '%u' in result:
result = result.replace('%u','\\u').decode('unicode_escape')
return result
print unquote_u('Tan%u0131m')
> Tanım
c'è un bug nella versione precedente in cui si spaventa a volte quando ci sono sia caratteri ASCII codificati che Unicode codificati nella stringa. Penso che sia specificamente quando ci sono personaggi della gamma superiore 128 come '\ xab' oltre a Unicode.
ad es. & Quot;% 5B% AB% u03E1% BB% 5D " causa questo errore.
Ho scoperto che se hai fatto prima quelli unicode, il problema sarebbe scomparso:
def unquote_u(source):
result = source
if '%u' in result:
result = result.replace('%u','\\u').decode('unicode_escape')
result = unquote(result)
return result
Hai un URL che utilizza un schema di codifica non standard , respinto dagli enti normativi ma ancora prodotto da alcuni encoder. La funzione Python urllib.parse.unquote ()
non può gestirle.
Creare il tuo decoder non è così difficile, per fortuna. Le voci % uhhhh
devono essere qui UTF-16 , quindi dobbiamo prendere coppie surrogate in considerazione. Ho anche visto i punti di codice % hh
mescolati, per maggiore confusione.
Con questo in mente, ecco un decodificatore che funziona sia in Python 2 che in Python 3, a condizione che tu passi un oggetto str
in Python 3 (Python 2 se ne frega di meno):
try:
# Python 3
from urllib.parse import unquote
unichr = chr
except ImportError:
# Python 2
from urllib import unquote
def unquote_unicode(string, _cache={}):
string = unquote(string) # handle two-digit %hh components first
parts = string.split(u'%u')
if len(parts) == 1:
return parts
r = [parts[0]]
append = r.append
for part in parts[1:]:
try:
digits = part[:4].lower()
if len(digits) < 4:
raise ValueError
ch = _cache.get(digits)
if ch is None:
ch = _cache[digits] = unichr(int(digits, 16))
if (
not r[-1] and
u'\uDC00' <= ch <= u'\uDFFF' and
u'\uD800' <= r[-2] <= u'\uDBFF'
):
# UTF-16 surrogate pair, replace with single non-BMP codepoint
r[-2] = (r[-2] + ch).encode(
'utf-16', 'surrogatepass').decode('utf-16')
else:
append(ch)
append(part[4:])
except ValueError:
append(u'%u')
append(part)
return u''.join(r)
La funzione è fortemente ispirata al .
Demo:
>>> print(unquote_unicode('Tan%u0131m'))
Tanım
>>> print(unquote_unicode('%u05D0%u05D9%u05DA%20%u05DE%u05DE%u05D9%u05E8%u05D9%u05DD%20%u05D0%u05EA%20%u05D4%u05D8%u05E7%u05E1%u05D8%20%u05D4%u05D6%u05D4'))
איך ממירים את הטקסט הזה
>>> print(unquote_unicode('%ud83c%udfd6')) # surrogate pair
🏖
>>> print(unquote_unicode('%ufoobar%u666')) # incomplete
%ufoobar%u666
La funzione funziona su Python 2 (testato su 2.4 - 2.7) e Python 3 (testato su 3.3 - 3.8).