Как заключить в кавычки строку Unicode в Python? - PullRequest
47 голосов
/ 19 ноября 2008

У меня есть строка в кодировке Unicode, например "Tanım", которая как-то кодируется как "Tan% u0131m". Как я могу преобразовать эту закодированную строку обратно в исходный Unicode. Очевидно, urllib.unquote не поддерживает юникод.

Ответы [ 5 ]

68 голосов
/ 19 ноября 2008

% uXXXX - это нестандартная схема кодирования , которая была отклонена w3c, несмотря на то, что реализация продолжает жить на земле JavaScript.

Похоже, более распространенным методом является кодирование строки в UTF-8, а затем% экранирования получаемых байтов с использованием% XX. Эта схема поддерживается urllib.unquote:

>>> urllib2.unquote("%0a")
'\n'

К сожалению, если вам действительно нужно для поддержки% uXXXX, вам, вероятно, придется свернуть свой собственный декодер. В противном случае, вероятно, будет гораздо предпочтительнее просто кодировать UTF-8 в кодировке Unicode, а затем% экранировать получающиеся байты.

Более полный пример:

>>> u"Tanım"
u'Tan\u0131m'
>>> url = urllib.quote(u"Tanım".encode('utf8'))
>>> urllib.unquote(url).decode('utf8')
u'Tan\u0131m'
10 голосов
/ 19 ноября 2008
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)
6 голосов
/ 19 ноября 2008

Это будет сделано, если вам абсолютно необходимо иметь это (я действительно согласен с криками «нестандартных»):

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
4 голосов
/ 16 декабря 2008

есть ошибка в вышеприведенной версии, когда она иногда выходит из строя, когда в строке присутствуют символы как в кодировке ascii, так и в кодировке Unicode. Я думаю, это особенно, когда есть символы из верхнего диапазона 128, такие как '\ xab' в дополнение к Unicode.

например. «% 5B% AB% u03E1% BB% 5D» вызывает эту ошибку.

Я обнаружил, что если вы сначала сделали Unicode, проблема исчезла:

def unquote_u(source):
  result = source
  if '%u' in result:
    result = result.replace('%u','\\u').decode('unicode_escape')
  result = unquote(result)
  return result
1 голос
/ 07 марта 2019

У вас есть URL с использованием нестандартной схемы кодирования , отклоненной органами стандартизации, но все еще производимой некоторыми кодировщиками. Функция Python urllib.parse.unquote() не может справиться с этим.

К счастью, создание собственного декодера не так сложно. Здесь %uhhhh записей означают UTF-16 кодовые точки, поэтому мы должны учитывать суррогатных пар . Я также видел смешанные %hh кодовые точки для дополнительной путаницы.

Имея это в виду, вот декодер, который работает как в Python 2, так и в Python 3, при условии, что вы передаете объект str в Python 3 (Python 2 не заботится):

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)

Функция в значительной степени вдохновлена ​​текущей реализацией стандартной библиотеки .

Демо-версия:

>>> 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

Функция работает на Python 2 (проверено на 2.4 - 2.7) и Python 3 (проверено на 3.3 - 3.8).

...