小写时python3 unicode失败

问题描述 投票:1回答:2

我在Python 3面临一个非常奇怪的问题:

>>> a = "abcé"
>>> a
'abcé'
>>> print(a)
abcé
>>> print(a.lower())
abc�

我不知道它来自哪里,但它不能小写unicode字符。请注意,我无法在任何地方重现该错误,这只是在我的一台计算机上,我得到以下问题。此外,同一台计算机上的python2正确打印abcé

此外,a.upper()正在返回ABCé而不是ABCÉ,因此它不会遇到与lower相同的问题。

有任何想法吗?

python string python-3.x unicode lowercase
2个回答
2
投票

你观察到的行为确实非常奇怪:字母“é”不受Python的str.upper()的影响,并由str.lower()变成了替代角色。同样奇怪的是,这似乎取决于环境,因为所述str方法没有表现出任何定位(即使这有时可能有意义,如土耳其地图“i”→“İ”的情况和“ı”→“我”),但始终使用Unicode的默认案例算法。

Possible explanation

对这种奇怪现象最可能的解释是Python不会“看到”与您相同的数据。正如Hansaplast在他们的回答中所写,终端和Python解释器之间可能存在编码不匹配。人们通常不必关心这一点,但是当你使用交互式解释器时,显示打字和打印字符的工作实际上并不是由Python执行的,而是由终端[模拟器]执行的,而这个附加层可以是有时问题的根源。

到底是怎么回事?我相信以下场景可以解释观察到的行为:

  • 您的终端配置为使用UTF-8。当您键入“é”时,它会将字节C3 A9发送到Python。当它从Python接收C3 A9时,它将显示“é”。
  • 但是,Python通过locale.getlocale()的返回值确认使用Latin-1。当它收到C3 A9时,它将其解码为“Ô,这是mojibake的常见情况。
  • UTF-8和Latin-1都是ASCII的超集,因此只要您只使用ASCII字符,这种错误配置就不是问题。当您键入“A”时,Python读取“A”,输出相同。

关于这种错误配置的真正令人讨厌的事情是它只在某些情况下可见。由于en- / decode的对称性,即使非ASCII字符也可能未被注意到。如果Python简单地回应它的输入,即。打印“é”,这将被终端解除为“é”,因此隐藏了错误。但是当以某种方式解释单个角色时 - 如str.upper()lower()--,可能会出现意想不到的事情。

在你的情况下,.upper()没有效果,因为“Ô已经是大写,而“©”是无壳的。这就是为什么'abcé'.upper()在屏幕上导致'ABCé'。但是,lowercasing产生“ã©”,Python编码为E3 A9。由于这不是有效的UTF-8字节序列,因此终端在解释它时失败并显示替换字符( )。

Solutions

如果这种解释是正确的,那么如何修复编码错误配置?

  • 对于交互式会话,Python使用环境变量(如LC_ALL)来设置STDIN / STDOUT的编码可能是有意义的。像export LC_ALL=en_US.utf8这样的行放在你的终端中运行的shell的启动脚本中,例如。 .bashrc中。从Python中更改语言环境无效,因为STD-stream编码在启动时设置,并且在调用locale.selocale()时不会更新。
  • 对于脚本,您可能不希望依赖环境变量。您可以围绕每个标准通道的二进制流创建一个新的io.TextIOWrappersys.stdin = open(sys.stdin.buffer.fileno(), encoding='utf8') sys.stdout = open(sys.stdout.buffer.fileno(), 'w', encoding='utf8') sys.stderr = open(sys.stderr.buffer.fileno(), 'w', encoding='utf8') (我不推荐这种解决方案用于交互式会话。特别是如果你输入错误的东西,你可以从难以恢复的情况进入。)

3
投票

我不完全确定这里发生了什么,但它看起来像python和你的终端之间的一些编码问题。

无论如何最佳做法是将所有内容保存在'utf-8'中以确保您可以从python中执行import localelocale.setlocale(locale.LC_ALL, 'en_US.UTF-8')或者执行export LC_ALL=en_US.utf8

我不是100%熟悉这些编码主题,所以也许编码专家有更好的答案/解释,但这应该解决你的情况。

© www.soinside.com 2019 - 2024. All rights reserved.