上游服务读取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
(â)。
✔
作为字节:e4 9c 94
e4 9c 94
作为latin1字符串:â
â
作为字节:c3 a2 c2 9c c2 94 我可以使用upstream.encode('ISO-8859-1').force_encoding('UTF-8')
来解决它,但是一旦解决了上游问题,它就会崩溃。
答案 0 :(得分:1)
几乎可以保证裸露的ISO 8859-1是无效的UTF-8。尝试先解码为ISO 8859-1,然后再解码为UTF-8,然后退回到仅解码为UTF-8(如果这会产生无效的字节序列),则适用于此特定情况。
更详细地讲,UTF-8编码严格限制了允许使用哪些非ASCII字符序列。在ISO-8859-1中,允许的模式极不可能出现,因为在这种编码中,它们表示类似common/config/base.php
之类的序列,后跟不可打印的控制字符或数学运算符,而这些序列根本不会出现在任何有效文本中。>
答案 1 :(得分:1)
基于 Mark Tolonen 的回答,同样在 Python 3 中:
def maybe_fix_encoding(utf8_string, possible_codec="cp1252"):
"""Attempts to fix mangled text caused by interpreting UTF8 as cp1252
(or other codec: https://docs.python.org/3/library/codecs.html)"""
try:
return utf8_string.encode(possible_codec).decode('utf8')
except UnicodeError:
return utf8_string
>>> maybe_fix_encoding("some normal text and some scandinavian characters æ ø å Æ Ø Å")
'some normal text and some scandinavian characters æ ø å Æ Ø Å'
答案 2 :(得分:0)
由于您知道它是如何变形的,因此可以尝试通过解码接收到的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)))
输出:
✔
✔