Расшифровка UTF-8 URL в Python

У меня есть строка вроде "pe%20to%C5%A3i%20mai". Когда я применяю к нему urllib.parse.unquote, я получаю "pe to\u0163i mai". Если я пытаюсь записать это в файл, я получаю именно эти символы, а не ожидаемый глиф.

Как я могу преобразовать строку в utf-8, чтобы вместо этого в файле у меня был правильный глиф?

Редактировать: я использую Python 3.2

Edit2: так что я понял, что urllib.parse.unquote работал правильно, и моя проблема на самом деле заключается в том, что я сериализовать в YAML с yaml.dump и это, кажется, все испортило. Зачем?

4 ответа

Решение

Обновление: если выходной файл является документом yaml, вы можете игнорировать \u0163 в этом. Экранирование Unicode действительно в документах yaml.

#!/usr/bin/env python3
import json

# json produces a subset of yaml
print(json.dumps('pe toţi mai')) # -> "pe to\u0163i mai"
print(json.dumps('pe toţi mai', ensure_ascii=False)) # -> "pe toţi mai"

Примечание: нет \u в последнем случае. Обе строки представляют одну и ту же строку Python.

yaml.dump() имеет аналогичную опцию: allow_unicode, Установите это True чтобы избежать Unicode Escape.


URL правильный. Вам не нужно ничего делать с этим:

#!/usr/bin/env python3
from urllib.parse import unquote

url =  "pe%20to%C5%A3i%20mai"
text = unquote(url)

with open('some_file', 'w', encoding='utf-8') as file:
    def p(line):
        print(line, file=file) # write line to file

    p(text)                # -> pe toţi mai
    p(repr(text))          # -> 'pe toţi mai'
    p(ascii(text))         # -> 'pe to\u0163i mai'

    p("pe to\u0163i mai")  # -> pe toţi mai
    p(r"pe to\u0163i mai") # -> pe to\u0163i mai
    #NOTE: r'' prefix

\u0163 последовательность может быть введена обработчиком ошибок кодировки символов:

with open('some_other_file', 'wb') as file: # write bytes
    file.write(text.encode('ascii', 'backslashreplace')) # -> pe to\u0163i mai

Или же:

with open('another', 'w', encoding='ascii', errors='backslashreplace') as file:
    file.write(text) # -> pe to\u0163i mai

Больше примеров:

# introduce some more \u escapes
b = r"pe to\u0163i mai ţţţ".encode('ascii', 'backslashreplace') # bytes
print(b.decode('ascii')) # -> pe to\u0163i mai \u0163\u0163\u0163
# remove unicode escapes
print(b.decode('unicode-escape')) # -> pe toţi mai ţţţ

Пытаться decode с помощью unicode_escape,

Например:

>>> print "pe to\u0163i mai".decode('unicode_escape')
pe toţi mai

Python 3

призвание urllib.parse.unquote возвращает строку Unicode уже:

>>> urllib.parse.unquote("pe%20to%C5%A3i%20mai")
'pe toţi mai'

Если вы не получите такой результат, это должно быть ошибка в вашем коде. Пожалуйста, оставьте свой код.

Python 2

использование decode чтобы получить строку Unicode из строки байтов:

>>> import urllib2
>>> print urllib2.unquote("pe%20to%C5%A3i%20mai").decode('utf-8')
pe toţi mai

Помните, что когда вы пишете строку Unicode в файл, вы должны снова ее кодировать. Вы можете выбрать запись в файл как UTF-8, но вы также можете выбрать другую кодировку, если хотите. Вы также должны помнить использовать ту же кодировку при чтении из файла. Вы можете найти codecs Модуль полезен для определения кодировки при чтении и записи в файлы.

>>> import urllib2, codecs
>>> s = urllib2.unquote("pe%20to%C5%A3i%20mai").decode('utf-8')

>>> # Write the string to a file.
>>> with codecs.open('test.txt', 'w', 'utf-8') as f:
...     f.write(s)

>>> # Read the string back from the file.
>>> with codecs.open('test.txt', 'r', 'utf-8') as f:
...     s2 = f.read()

Одна потенциально запутанная проблема заключается в том, что в интерактивном интерпретаторе строки Unicode иногда отображаются с использованием \uxxxx обозначение вместо реальных символов:

>>> s
u'pe to\u0163i mai'
>>> print s
pe toţi mai

Это не значит, что строка "неправильная". Просто так работает переводчик.

urllib.parse.unquote вернул правильную строку UTF-8 и записал, что прямо в возвращенный файл дал ожидаемый результат. Проблема была с ямлом. По умолчанию это не кодирует с UTF-8.

Мое решение было сделать:

yaml.dump("pe%20to%C5%A3i%20mai",encoding="utf-8").decode("unicode-escape")

Спасибо JF Себастьяну и Марку Байерсу за то, что они задали мне правильные вопросы, которые помогли мне разобраться в проблеме!

Другие вопросы по тегам