Как обнаружить и исправить неверную кодировку - PullRequest
0 голосов
/ 25 июня 2019

Служба восходящего потока считывает поток байтов UTF-8, предполагает , что это ISO-8859-1, применяет ISO-8859-1 к кодировке UTF-8 и отправляет их в мою службу, помеченнуюкак UTF-8.

вышестоящая служба находится вне моего контроля.Они могут это исправить, возможно, это никогда не будет исправлено.

Я знаю, что могу исправить кодировку, применив UTF-8 к кодировке ISO-8859-1, затем пометив байты как UTF-8.Но что произойдет, если мой апстрим исправит их проблему?

Есть ли способ обнаружить эту проблему и исправить кодировку только тогда, когда я найду плохую кодировку?

Я тоже не уверен, что кодировкой восходящего потока является ISO-8859-1.Я думаю, что исходным кодом является perl, так что кодирование имеет смысл, и каждый пример, который я пробовал, правильно декодируется, когда я применяю кодировку ISO-8859-1.


Когда источник отправляет e4 9c 94 (✔) в мой апстрим, мой апстрим отправляет мне c3 a2 c2 9c c2 94 (â).

  • utf-8 string как байты: e4 9c 94
  • байты e4 9c 94 как строка latin1: â
  • строка utf-8 â как байты: c3 a2 c2 9c c2 94

Я могу это исправить, применив upstream.encode('ISO-8859-1').force_encoding('UTF-8'), но он сломается, как только проблема с вышестоящей версией будет исправлена.

Ответы [ 2 ]

1 голос
/ 27 июня 2019

Голый ISO 8859-1 почти гарантированно является недействительным UTF-8. Попытка декодировать как ISO 8859-1, а затем как UTF-8, и возврат к простому декодированию как UTF-8, если это приводит к неправильным последовательностям байтов, должно работать для этого конкретного случая.

Более подробно, кодировка UTF-8 строго ограничивает, какие последовательности символов не ASCII разрешены. Разрешенные шаблоны крайне маловероятны в ISO-8859-1, потому что в этом кодировании они представляют последовательности, подобные Ã, за которыми следует непечатаемый управляющий символ или математический оператор, которые просто не встречаются в каком-либо допустимом тексте.

0 голосов
/ 27 июня 2019

Поскольку вы знаете, как оно искажено, вы можете попытаться его деформировать, расшифровав принятые байты UTF-8, закодировав его в latin1 и снова расшифровав как UTF-8. Только ваши искаженные строки, чистые строки ASCII или очень маловероятные комбинации символов latin-1 будут успешно декодированы дважды. Если это декодирование не удается, предположим, что восходящий поток был зафиксирован, и просто декодируйте один раз как UTF-8. Чистая строка ASCII будет корректно декодироваться любым из методов, поэтому здесь также нет проблем. Существуют действующие последовательности в кодировке UTF-8, которые выдерживают двойное декодирование, но вряд ли они встречаются в обычном тексте.

Вот пример на Python (вы не упомянули язык ...):

# Assume bytes are latin1, but return encoded UTF-8.
def bad(b):
    return b.decode('latin1').encode('utf8')

# Assume bytes are UTF-8, and pass them along.
def good(b):
    return b

def decoder(b):
    try:
        return b.decode('utf8').encode('latin1').decode('utf8')
    except UnicodeError:
        return b.decode('utf8')

b = '✔'.encode('utf8')
print(decoder(bad(b)))
print(decoder(good(b)))

Выход:

✔
✔
...