Python 跳过/删除不可解码字符

1 投票
2 回答
2647 浏览
提问于 2025-04-18 08:27

我现在正在处理一些客户输入的字符串,这些字符串是作为json的一部分。我已经把这些字符串做成了一个字典,现在我只需要做:

json.dumps(some_dict)

问题是,有些客户输入的数据似乎出现了乱码,试图把它们转成json时就会出错:

{'FIRST_NAME': 'sdffg\xed', 'LAST_NAME': 'sdfsadf'}

然后我就得到了:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xed in position 6: ordinal not in range(128)

我无法控制数据的来源,所以不能提前防止这种情况发生。既然这些坏数据已经存在了,我在想是否可以用某个占位符字符替换掉那些未知或不好的字符,或者直接删除它们。我该怎么做呢?

2 个回答

2

json.dumps这个函数会尝试把内容转换成ASCII格式(除非你指定了其他编码)。所以,你需要确保你的字符串能够被转换成ASCII格式。幸运的是,unicode()这个函数在没有指定编码的情况下,会把字符串自动转换成ASCII格式。所以……

copy = {}
for k, v in d.items():
    copy[k] = unicode(v, errors='ignore')

json.dumps(copy)
6

{'FIRST_NAME': 'sdffg\xed', 'LAST_NAME': 'sdfsadf'}

这是一个Python字典,里面的键和值都是字节字符串。字节字符串在JSON中是无法表示的,因为JSON没有字节的概念。JSON中的字符串值总是Unicode格式的,所以如果想要准确地重现一个Python字典,你需要确保所有的文本键和值都是unicodeu'...')字符串。

Python允许你使用'FIRST_NAME',因为它只包含普通的ASCII字符;大多数常见的字节编码都是ASCII的超集,所以Python可以安全地将这个字符串隐式解码为ASCII。但对于那些包含0x00到0x7F范围之外的字节的字符串,比如'sdffg\xed',情况就不一样了。在把它放进字典之前,你应该先用.decode将字节str解码为unicode字符串。(实际上,你应该确保在整个应用程序处理中,文本数据都保持为Unicode字符串,只有在从非Unicode源加载输入时,或者输出需要发送到非Unicode目标时,才转换为字节字符串。所以在这个阶段,你不应该在字典中有字节内容。检查一下输入来源 - 你可能应该在更早的地方进行decode()步骤。)

你可以通过以下方式解码为Unicode,并跳过或替换非ASCII字符:

>>> 'sdffg\xed'.decode('ascii', 'ignore')
u'sdffg'
>>> 'sdffg\xed'.decode('ascii', 'replace')
u'sdffg\uFFFD' # U+FFFD = �. Unicode string, json.dump can serialise OK

不过,丢掉可能有用的数据似乎有点可惜。如果你能猜到创建字节字符串时使用的编码,你可以保留那些可以恢复的非ASCII字符。如果字节0xED代表字符U+00ED(í),那么.decode('iso-8859-1')或者可能.decode('cp1252')可能就是你需要的编码。

撰写回答