在我的 python 脚本中,我从一个我没有编写的函数中得到了一些字符串。它的编码各不相同。我需要将其转换为 ascii 格式。有没有一些万无一失的方法来做到这一点?我不介意用空格或其他东西替换非ASCII字符......
5 回答
如果你想要一个 ASCII 字符串明确地代表你所拥有的,而不丢失任何信息,答案很简单:
不要纠结于编码/解码,使用repr()
函数(Python 2.X)或ascii()
函数(Python 3.x)。
你说“它的编码不同”。我猜你所说的“它”是指 Python 2.x 的“字符串”,它实际上是一个字节序列。
回答第一部分:如果您不知道该编码字符串的编码,那么不,根本没有办法对它做任何有意义的事情*。如果您确实知道编码,那么第一步是将您的编码转换str
为unicode
:
encoded_string = i_have_no_control()
the_encoding = 'utf-8' # for the sake of example
text = unicode(encoded_string, the_encoding)
然后,如果您愿意,您可以将您的 unicode 对象重新编码为 ASCII。
ascii_garbage = text.encode('ascii', 'replace')
* 有猜测编码的启发式方法,但速度慢且不可靠。这是Python 中的一次极好的尝试。
我会尝试规范化字符串然后对其进行编码。关于什么 :
import unicodedata
s = u"éèêàùçÇ"
print unicodedata.normalize('NFKD',s).encode('ascii','ignore')
这仅在您将 unicode 作为输入时才有效。因此,您必须知道可以对函数输出进行编码和解码。如果不这样做,则有编码检测启发式,但在短字符串上,则不可靠。
当然,您可能很幸运,函数输出依赖于各种未知编码,但使用 ascii 作为代码库,因此它们将为 0 到 127 的字节分配相同的值(如 utf-8)。
在这种情况下,您可以通过使用OrderedSets过滤掉不需要的字符:
import string.printable # asccii chars
print "".join(OrderedSet(string.printable) & OrderedSet(s))
或者,如果您想要空白:
print("".join(((char if char in string.printable else " ") for char in s )))
“翻译”可以帮助你做同样的事情。
知道你是否如此幸运的唯一方法就是尝试一下......有时,任何开发人员都需要一个大幸运的日子:-)
“万无一失”的意思是,即使是最模糊、不可能的输入,该函数也不会失败——这意味着,你可以给函数提供随机二进制数据,它永远不会失败,不管怎样。这就是“万无一失”的意思。
然后该函数应继续尽力转换为目标编码。如果它必须把它不理解的垃圾都扔掉,那很好,实际上是最理想的结果。为什么要尝试打捞所有的垃圾?只是丢弃垃圾。告诉用户他不仅仅是一个使用微软任何东西的白痴,而是一个使用非标准微软任何东西的非标准白痴……或者试图发送二进制数据!
我也有同样的需求(尽管我的需求是在 PHP 中),而且我也有一些用户至少和我一样愚蠢,有时甚至更多;然而,他们肯定更好,毫无疑问更有耐心。
到目前为止,我发现的最好的底线是(在 PHP 5.3 中):
$fixed_string = iconv('ISO-8859-1', 'UTF-8//IGNORE//TRANSLATE', $in_string);
这会尝试翻译它可以翻译的任何内容,并简单地丢弃所有垃圾,从而产生合法的 UTF-8 字符串输出。我也无法破坏它或导致它失败或拒绝任何传入的文本或数据,即使向它提供二进制垃圾数据也是如此。
找到 iconv() 并让它工作很容易;如此令人抓狂和浪费的是阅读所有程序员在处理这种编码惨败时似乎支持的所有垃圾和向后弯曲的白痴。老派编程中令人羡慕的(和受人尊敬的)“连枷烧白痴”的心态变成了什么?让我们回到基础。使用 iconv() 并扔掉他们的垃圾,当告诉他们你扔掉了他们的垃圾时不要害羞——简而言之,不要对那些喂你垃圾的白痴进行鞭打。你可以告诉他们我告诉过你的。
如果您只想保留与 ASCII 兼容的字符并丢弃其余字符,那么在大多数编码中,归结为删除所有设置了高位的字符——即值超过 127 的字符。这是有效的,因为几乎所有字符集是 7 位 ASCII 的扩展。
如果它是一个普通的字符串(即 not unicode
),您需要将其解码为任意字符集(例如iso-8859-1
因为它接受任何字节值),然后使用 ascii 编码,使用ignore
orreplace
选项表示错误:
>>> orig = '1ä2äö3öü4ü'
>>> orig.decode('iso-8859-1').encode('ascii', 'ignore')
'1234'
>>> orig.decode('iso-8859-1').encode('ascii', 'replace')
'1??2????3????4??'
解码步骤是必要的,因为您需要一个unicode字符串才能使用编码。如果你已经有一个 Unicode 字符串,那就更简单了:
>>> orig = u'1ä2äö3öü4ü'
>>> orig.encode('ascii', 'ignore')
'1234'
>>> orig.encode('ascii', 'replace')
'1??2????3????4??'