在 Windows 中更改 Python 3 中的“区域设置首选编码”
Posted
技术标签:
【中文标题】在 Windows 中更改 Python 3 中的“区域设置首选编码”【英文标题】:Changing the “locale preferred encoding” in Python 3 in Windows 【发布时间】:2015-10-06 19:31:54 【问题描述】:我正在使用 Python 3(最近从 Python 2 切换)。我的代码通常在 Linux 上运行,但有时(不经常)在 Windows 上运行。根据open()
的Python 3 文档,如果未提供encoding
参数,则文本文件的默认编码来自locale.getpreferredencoding()
。对于我的项目,我希望这个默认值是utf-8
,无论它在什么操作系统上运行(目前,对于 Linux,它始终是 UTF-8,但对于 Windows 不是)。该项目有很多对open()
的调用,我不想将encoding='utf-8'
添加到所有这些调用中。因此,我想在 Windows 中更改语言环境的首选编码,就像 Python 3 所看到的那样。
我发现了一个以前的问题
“Changing the "locale preferred encoding"”,它有一个公认的答案,所以我认为我很高兴。但不幸的是,该答案中的建议命令及其第一条评论都不适用于 Windows。具体来说,接受的答案和它的第一条评论建议运行chcp 65001
和set PYTHONIOENCODING=UTF-8
,我都试过了。请从我的 cmd 窗口查看以下脚本:
> py -i
Python 3.4.3 ...
>>> f = open('foo.txt', 'w')
>>> f.encoding
'cp1252'
>>> exit()
> chcp 65001
Active code page: 65001
> py -i
Python 3.4.3 ...
>>> f = open('foo.txt', 'w')
>>> f.encoding
'cp1252'
>>> exit()
> set PYTHONIOENCODING=UTF-8
> py -i
Python 3.4.3 ...
>>> f = open('foo.txt', 'w')
>>> f.encoding
'cp1252'
>>> exit()
请注意,即使在两个建议的命令之后,我打开的文件的编码仍然是cp1252
,而不是预期的utf-8
。
【问题讨论】:
也许这只是我的风格,但我更愿意编写一个包装器 open() 函数,您可以在其中指定编码。 不要使用chcp 65001
。 Windows 控制台不正确地支持 UTF-8,而且它也没有做你想做的事。 locale.getpreferredencoding
与控制台代码页无关;它基于 Windows 语言环境的 ANSI 编码。例如,如果您调用 Win32 CreateFileA
(ANSI) 而不是 CreateFileW
(UTF-16),则文件路径字符串将被解码为 ANSI 字符串(例如 Windows-1252)。 Windows 不允许将 UTF-8 用作 ANSI 字符集,C 运行时也不允许将 UTF-8 用于语言环境。
@eryksun 感谢您提供的信息,但它对我来说有太多特定于 Windows 的行话。我很少使用 Windows。我想要的只是一种对 Windows 8 或 Python 3 说的方式:“亲爱的 Windows 8 / Python 3,请注意,这台计算机上的所有文本文件都应该毫无例外地以 UTF-8 编码。请记住这个事实将来打开文本文件时。谢谢。”
@walrus,不存在这样的东西。 Windows 上的原生字符串格式是 UTF-16,使用 16 位 wchar_t
字符串。 Windows API 仅支持旧版 ANSI API 的 8 位编码,遗憾的是它不允许 UTF-8。 Python 的首选编码只是调用GetACP
来获取ANSI 代码页。我同情你并希望io.TextIOWrapper
在所有平台上都默认为 UTF-8(你对 Linux 的假设也不总是有效的)。就目前情况而言,您需要一个包装函数,如前所述。
稍微努力一下就可以找到TextIOWrapper
源,并在其中看到_Py_device_encoding
是使用Windows 控制台代码页(GetConsoleCP
) 的,但仅适用于stdin、stdout 和stderr .否则它调用getpreferredencoding
,它调用_getdefaultlocale
,因此调用GetACP
。
【参考方案1】:
从 python3.5.1 开始,这个 hack 看起来像这样:
import _locale
_locale._getdefaultlocale = (lambda *args: ['en_US', 'utf8'])
此后打开的所有文件都将假定默认编码为utf8
。
【讨论】:
或者更好的是,utf_8_sig
,因为它会处理一些 Windows 编辑器倾向于注入文件的 BOM 字符,即使是像 utf8
这样的中性字节编码。【参考方案2】:
我知道这是一个真正的 hacky 解决方法,但您可以像这样重新定义 locale.getpreferredencoding()
函数:
import locale
def getpreferredencoding(do_setlocale = True):
return "utf-8"
locale.getpreferredencoding = getpreferredencoding
如果你早点运行它,所有打开的文件(至少在我在 win xp 机器上的测试中)都以 utf-8 格式打开,并且由于这会覆盖模块方法,这将适用于所有平台。
【讨论】:
我在 python 3.5.1 和 windows 7 和 have a look 上测试了我最终得到的结果。 这似乎不起作用,至少在我的 Windows 10 和 pyhton 3.6.8 上 @sandwood 看看上面的 axils 答案,了解在 python 3.5 之后工作的答案 感谢您的帮助。是的@axil 答案适用于 3.6.8 奇怪的是对应于 3.6 的 python 文档,你的答案应该有效。【参考方案3】:帖子已过时,但问题仍然存在(在 Python 3.7 和 Windows 10 下)。
我对解决方案进行了如下改进,确保不会覆盖语言/国家/地区部分,而只会覆盖编码,并确保仅在 Windows 下完成:
if os.name == "nt":
import _locale
_locale._gdl_bak = _locale._getdefaultlocale
_locale._getdefaultlocale = (lambda *args: (_locale._gdl_bak()[0], 'utf8'))
希望这会有所帮助...
【讨论】:
【参考方案4】:如果您愿意,可以在窗口中将区域设置全局设置为 UTF-8,如下所示:
Control panel
-> Clock and Region
-> Region
-> Administrative
-> Change system locale
-> 检查Beta: Use Unicode UTF-8 ...
在此之后并重新启动,我确认 locale.getpreferredencoding()
返回 'cp65001'
(=UTF-8) 并且像 open
这样的函数默认为 UTF-8。
【讨论】:
以上是关于在 Windows 中更改 Python 3 中的“区域设置首选编码”的主要内容,如果未能解决你的问题,请参考以下文章
在 Python 中编写适用于 Windows 中的 Python 2.7+ 和 Python 3.3+ 的 .CSV 文件