这个问题有多个方面。根本问题是你想要输出到哪个字符集。你可能还需要确定输入字符集。
使用明确的
encoding="..."
将 Python 的内部 Unicode 表示转换为该编码,可以通过
print
或
write
将其打印到文件中。如果输出包含不受该编码支持的字符,则会出现
UnicodeEncodeError
。例如,如果编码为
"cp1252"
,则无法将俄语、中文、印度语、希伯来语、阿拉伯语或表情符号等除了一组约200个西方字符以外的任何内容写入文件,因为这种限制的8位字符集没有办法表示这些字符。
基本上,任何8位字符集都会出现相同的问题,包括几乎所有旧版 Windows 代码页(437、850、1250、1251等等),尽管其中一些支持英语之外的一些其他脚本(1251支持西里尔语,因此您可以写俄语、乌克兰语、塞尔维亚语、保加利亚语等)。8位编码只有最多256个字符代码,没有办法表示不在其中的字符。
也许现在是阅读Joel Spolsky的《绝对必要:关于Unicode和字符集,每个软件开发者都必须知道的最低限度(别找借口了!)》的好时机。
在终端无法打印Unicode的平台上(现在只有Windows存在这个问题,虽然如果你喜欢复古计算机,在上个世纪的其他平台上也存在这个问题),尝试print
Unicode字符串也会产生错误,或输出乱码。如果你看到的是Héllö
而不是Héllö
,那么这就是你的问题。
简而言之,你需要知道:
如果您在这里,可能其中一个问题的答案不是“UTF-8”。尽管先前的标准是ISO-8859-1(又称为Latin-1),最近的Windows代码页1252,但这越来越成为Web页面的主流编码。
前进时,基本上希望所有文本数据都是Unicode,除了一些边缘用例。通常,这意味着使用UTF-8,但在Windows上(或者如果需要Java兼容性),UTF-16也可能有用,尽管有点繁琐。 (还有几种其他Unicode序列化格式,在特定情况下可能有用。UTF-32在技术上很简单,但占用更多内存;UTF-7在一些网络协议中使用,其中需要传输7位ASCII。)
也许还可以参见
https://utf8everywhere.org/
当然,如果要将内容打印到文件中,您还需要使用能够正确显示它的工具来检查该文件。一个常见的错误是使用仅显示当前选定系统编码或试图猜测编码但猜错的工具打开文件。再次查看使用Windows代码页1252查看UTF-8文本的常见症状会导致例如
Héllö
显示为
Héllö
。
如果字符数据的编码未知,则没有简单的方法可以自动确定它。如果您知道文本应该表示什么,您可能可以推断出来,但这通常是一个需要一些猜测的手动过程。(像
chardet
和
ftfy
这样的自动工具可以帮助,但它们有时也会出错。)
为了确定你正在查看的编码方式,如果你能够识别一个字符中的单个字节,但该字符未正确显示,则会很有帮助。例如,如果你正在查看
H\x8ell\x9a
,但期望它表示
Héllö
,则可以在翻译表中查找这些字节。我已经发布了这样一张表格
https://tripleee.github.io/8bit,在这个例子中,它可能是旧版Mac 8位字符集之一;有了更多数据点,也许你可以将其缩小到其中之一(如果不能,实际上任何一个都可以,因为你关心的所有代码点都映射到相同的Unicode字符)。
大多数平台上的Python 3默认使用UTF-8进行所有输入和输出,但在Windows上,情况通常不是这样。它将默认使用系统的默认编码方式(在某些Microsoft文档中仍被误导性地称为“ANSI代码页”),这取决于许多因素。在西方系统上,开箱即用的默认编码方式通常是Windows代码页1252。(早期的Python版本有稍微不同的期望,在Python 2中,内部字符串表示不是Unicode。)
如果你在Windows上编写UTF-8文本文件,可能需要指定
encoding="utf-8-sig"
,这会在文件开头添加BOM序列。严格来说这不是必要或正确的,但某些Windows工具需要它才能正确识别编码。
这里的一些早期答案建议盲目应用某些编码,但希望这可以帮助你理解这通常不是正确的方法,并了解如何找出而不是猜测要使用哪种编码。