Декодирование строк в кодировке Юникод с помощью целых escape-последовательностей с 10 целыми числами - PullRequest
0 голосов
/ 27 марта 2020

В качестве входных данных я получаю строки, подобные этой

Funda\195\131\194\167\195\131\194\163o

, которые я получаю от службы Cymru Whois:

$ dig +short AS10417.asn.cymru.com TXT
"10417 | BR | lacnic | 2000-02-15 | Funda\195\131\194\167\195\131\194\163o de Desenvolvimento da Pesquisa, BR"

Правильно расшифровано, что приведет к:

Fundação

В шестнадцатеричной записи это:

b'\xc3\xa7\xc3\xa3'

, где 0xc3 - 195, 0xa7 - 167 и 0xa3 - 163, что соответствует номерам первого и последнего символа каждой четверки.

Итак, \195\131\194\167 - это ç и \195\131\194\163. Похоже, Python не может декодировать это, по крайней мере, с параметрами по умолчанию.

Является ли этот вид кодирования обычным и есть ли какие-либо встроенные функции в Python для декодирования этого в общем (не указывается c к этой строке, конечно)?

1 Ответ

3 голосов
/ 27 марта 2020

Хитрость здесь в том, чтобы использовать пользовательскую процедуру замены в re.sub:

Если repl является функцией, она вызывается для каждого неперекрывающегося вхождения pattern. Функция принимает один аргумент объекта сопоставления и возвращает строку замены.

Чтобы преобразовать строку в печатные символы, кодирует ее в bytes, используя latin1, что сохраняет все буквенные байтовые коды, а затем декодирует это как UTF-8:

import re

text = r'Funda\195\131\194\167\195\131\194\163o'

print (bytes('Fundação','utf8')) # This is our target
print (bytes(re.sub (r'\\(\d+)', lambda x: chr(int(x.group(1))), text).encode('latin1')).decode('utf-8'))

Однако ваш текст не просто кодируется в UTF-8, а кодируется !

b'Funda\xc3\xa7\xc3\xa3o'
Fundação

, поэтому декодирование его в UTF-8 дает другую строку в кодировке UTF-8. Нам нужно перевести дважды :

# This first line prints the byte values so you can compare it to the UTF-8 target:
print (bytes(re.sub (r'\\(\d+)', lambda x: chr(int(x.group(1))), text).encode('latin1')).decode('utf-8').encode('latin1'))

print (bytes(re.sub (r'\\(\d+)', lambda x: chr(int(x.group(1))), text).encode('latin1')).decode('utf-8').encode('latin1').decode('utf8'))

, чтобы наконец получить вывод:

b'Funda\xc3\xa7\xc3\xa3o'
Fundação
...