Исходя из ваших симптомов, вы работаете на Python 2. Вызов encode
на Python 2 str
почти всегда бессмыслен.
У вас две проблемы;тот, который вы нажмете сейчас, и тот, кого вы ударите, если исправите свой текущий код.
Ваша первая проблема line
- уже a str
in (очевидно) UTF-8 закодировал байты , а не unicode
, поэтому encode
неявно, декодирует с кодировкой Python по умолчанию (ASCII; это не локаль, специфичная для моих знаний, и эторедкая установка Python 2, которая использует что-либо еще), затем перекодирует с указанным кодеком (или по умолчанию, если не указан).По сути, line
уже был в кодировке UTF-8, вы сказали ему кодировать снова как UTF-8, но это бессмысленно, поэтому Python сначала попытался decode
в качестве ASCII и потерпел неудачу еще до того, как попыталсяencode
, как вы указали.
Решение этой проблемы состоит в том, чтобы просто не encode
line
вообще ;он уже в кодировке UTF-8, так что вы уже золотой.
Ваша вторая проблема (с которой вы еще не сталкивались, но вам придется) заключается в том, что вы звоните encode
на group(4)
результат.Но, конечно, поскольку входное значение было str
, группа тоже str
, и вы столкнетесь с той же проблемой, пытаясь encode
a str
;поскольку группа пришла из необработанных байтов в кодировке UTF-8, ее части, не относящиеся к ASCII, вызывают UnicodeDecodeError
на этапе неявного декодирования перед кодированием.
Причина:
import sys
reload(sys)
sys.setdefaultencoding('UTF8')
работает так, что он (опасно) изменяет шаг неявного декодирования для использования UTF-8, поэтому все ваши вызовы encode
теперь выполняют неявный decode
с UTF-8 вместо ASCII;decode
и encode
в основном бессмысленны, поскольку все, что он делает, это возвращает оригинал str
после подтверждения его законного UTF-8 посредством decode
, используя его как таковой, и в противном случае действует как дорогостоящий неоперативный оператор..
Чтобы устранить вторую проблему, просто измените:
m.group(4).encode()
на:
m.group(4)
В результате ваш окончательный код будет выглядеть так:
result = re.sub(r'(Start:\s*)([^:]+)(:\s*)([^:]+)',
lambda m: m.group(1) + m.group(2) + m.group(3) + hashlib.sha512(m.group(4)).hexdigest(),
line)
При желании, если вы хотите подтвердить свое ожидание того, что line
фактически является байтами в кодировке UTF-8, добавьте следующую строку над , что re.sub
:
try:
line.decode('utf-8')
except Exception as e:
sys.exit("line (of type {!r}) not decodable as UTF-8: {}".format(line.__class__.__name__, e))
что приведет к немедленному завершению работы программы, если указанные данные не являются допустимыми UTF-8 (а также сообщит вам, что типа line
, так что вы можете точно убедиться, действительно ли это str
или unicode
, так какstr
означает, что вы выбрали неправильный кодек, а unicode
означает, что ваши входные данные не соответствуют ожидаемому типу).