当前位置: 首页 > 面试题库 >

Python,Windows控制台和编码(cp 850 vs cp1252)

有品
2023-03-14
问题内容

我以为我知道编码和Python的所有知识,但是今天我遇到了一个奇怪的问题:尽管控制台设置为代码页850-并且Python正确报告了该代码-
我在命令行上输入的参数似乎已编码在代码页1252中如果尝试使用sys.stdin.encoding对其进行解码,则会得到错误的结果。如果我假设为“
cp1252”,而忽略sys.stdout.encoding报告的内容,则它将起作用。

我是否缺少某些内容,或者这是Python中的错误?Windows?注意:我在Windows 7 EN上运行Python
2.6.6,语言环境设置为French(Switzerland)。

在下面的测试程序中,我检查字面量是否正确解释并可以打印-可以。但是我在命令行上传递的所有值似乎都被错误地编码:

#!/usr/bin/python
# -*- encoding: utf-8 -*-
import sys

literal_mb = 'utf-8 literal:   üèéÃÂç€ÈÚ'
literal_u = u'unicode literal: üèéÃÂç€ÈÚ'
print "Testing literals"
print literal_mb.decode('utf-8').encode(sys.stdout.encoding,'replace')
print literal_u.encode(sys.stdout.encoding,'replace')

print "Testing arguments ( stdin/out encodings:",sys.stdin.encoding,"/",sys.stdout.encoding,")"
for i in range(1,len(sys.argv)):
    arg = sys.argv[i]
    print "arg",i,":",arg
    for ch in arg:
        print "  ",ch,"->",ord(ch),
        if ord(ch)>=128 and sys.stdin.encoding == 'cp850':
            print "<-",ch.decode('cp1252').encode(sys.stdout.encoding,'replace'),"[assuming input was actually cp1252 ]"
        else:
            print ""

在新创建的控制台中,运行时

C:\dev>test-encoding.py abcé€

我得到以下输出

Testing literals
utf-8 literal:   üèéÃÂç?ÈÚ
unicode literal: üèéÃÂç?ÈÚ
Testing arguments ( stdin/out encodings: cp850 / cp850 )
arg 1 : abcÚÇ
   a -> 97
   b -> 98
   c -> 99
   Ú -> 233 <- é [assuming input was actually cp1252 ]
   Ç -> 128 <- ? [assuming input was actually cp1252 ]

而我希望第4个字符的序数值为 130
而不是233(请参见代码页850和1252)。

注意:欧元符号128的值是一个谜-因为cp850没有它。 否则,“?” 符合预期-cp850无法打印字符,并且在转换中使用了“替换”。

如果我通过发出chcp 1252并运行相同的命令将控制台的代码页更改为1252 ,我(正确)获得了

Testing literals
utf-8 literal:   üèéÃÂç€ÈÚ
unicode literal: üèéÃÂç€ÈÚ
Testing arguments ( stdin/out encodings: cp1252 / cp1252 )
arg 1 : abcé€
   a -> 97
   b -> 98
   c -> 99
   é -> 233
   € -> 128

有什么想法我想念的吗?

编辑1:
我刚刚通过阅读sys.stdin进行了测试。这可以按预期工作:在cp850中,键入’é’会导致序数值为130。因此,问题实际上仅在于命令行。那么,命令行与标准输入是否有所不同?

编辑2: 似乎我输入了错误的关键字。我在SO上找到了另一个非常接近的主题:从Windows上的Python
2.x中的命令行参数读取Unicode字符。但是,如果命令行没有像sys.stdin那样进行编码,并且由于sys.getdefaultencoding()报告为“
ascii”,则似乎无法知道其实际编码。我发现使用win32扩展的答案很hacky。


问题答案:

回复自己:

在Windows上,控制台使用的编码(即sys.stdin / out的编码)不同于各种OS提供的字符串的编码-
通过os.getenv(),sys.argv等获得,当然还有更多。

sys.getdefaultencoding()提供的编码确实是这样-
一种默认值,由Python开发人员选择,以匹配解释器在极端情况下使用的“最合理的编码”。我在Python 2.6上获得了“
ascii”,并尝试了可移植的Python 3.1,产生了“ utf-8”。两者都不是我们想要的-它们只是编码转换函数的后备。

正如该页面所陈述的那样,操作系统提供的字符串所使用的编码由活动代码页(ACP)控制。由于Python没有本地函数来检索它,因此我不得不使用ctypes:

from ctypes import cdll
os_encoding = 'cp' + str(cdll.kernel32.GetACP())

编辑:
但是正如Jacek所建议的那样,实际上还有一种更健壮和Pythonic的方式可以做到这一点(语义需要验证,但在证明错误之前,我将使用此方法)

import locale
os_encoding = locale.getpreferredencoding()
# This returns 'cp1252' on my system, yay!

接着

u_argv = [x.decode(os_encoding) for x in sys.argv]
u_env = os.getenv('myvar').decode(os_encoding)

在我的系统上,os_encoding = 'cp1252'它可以正常工作。我非常确定这会在其他平台上中断,因此请随时进行编辑并使它更通用。我们当然需要Windows报告的ACP与Python编码名称之间的某种转换表,这比仅在’cp’之前更好。

不幸的是,这是一种hack,尽管我发现它比该ActiveState代码食谱(与我的问题的编辑2中提到的SO问题相关联)所建议的侵入性要小。我在这里看到的优点是,它可以应用于os.getenv(),而不仅可以应用于sys.argv。



 类似资料:
  • 问题内容: 当我尝试在控制台中打印字符串时,出现错误。我认为这是因为Windows控制台不接受仅字符。最好的办法是什么?有什么方法可以使Python自动打印?而不是在这种情况下失败? 问题答案:

  • 问题内容: 我们尝试在Windows上使用Java和UTF-8。该应用程序在控制台上写入日志,我们希望对日志使用UTF-8,因为我们的应用程序具有国际化的日志。 可以配置JVM,使其使用JVM的参数生成UTF-8 。它工作正常,但Windows控制台上的输出出现乱码。 然后,我们可以将控制台的代码页设置为65001(),但是在这种情况下,文件将无法工作。这意味着当我们尝试通过脚本(名为start.

  • 问题内容: 以下代码 在Windows下的Java控制台上,在“开始”和“结束”之间产生一个空行,但是在运行MacOS或Linux时可以正常工作。写入文件而不是使用sysout时同样如此。我试过多台Windows机器。我是通过eclipse还是通过cmd执行该方法都没有关系。 当您将“ 1234”更改为“ 1234”或“ 12g4”时,或者运行次数大于/小于936时,它将在所有OS上正常工作。 任

  • 我使用Spring Boot,我已经读到应该在日志文件或控制台打印出默认值--但我的日志中没有任何内容。我使用putty连接,连接是找到的,但我不知道凭据(密码)。为了让它工作,我能做什么提示吗? [编辑]我还将其添加到Application.Properties文件的行中: 但毫无效果。

  • 我无法在Eclipse中运行python控制台。我下载了Pydev,设置了一个解释器和一个PYTHONPATH并导入了一个项目,一个Django项目。我将项目设置为Django的一个,然后我尝试右键单击带有Django环境的Project-->Django-->Shell。 我在控制台中出现了以下错误: 如果我尝试打开一个Windows shell并执行通常的python manage.py sh

  • 在JupyterLab中,我希望将代码从编辑器发送到Python控制台执行,最好使用键盘快捷键。文档似乎没有提供实现这一点的方法,但它是IDE的一个基本方面,我认为这是可能的。

  • 问题内容: Java如何确定用于的编码? 给定以下类别: 它被保存为UTF-8并在Windows系统上进行编译。 然后在git-bash控制台上(使用UTF-8字符集),我这样做: 这里发生了什么? 显然,java检查它是否连接到终端,并在这种情况下更改其编码。有没有一种方法可以迫使Java简单地输出普通的UTF-8? 我也使用cmd控制台尝试了相同的操作。重定向STDOUT似乎没有任何区别。如果

  • 控制台 命令进入根目录执行 app/console - - - - - - - - - - - - - - - - - \ \ \ \ - - - - - - / - - - - - / \ / / - - - / / - - - - - \ \ \ \ \ \ \- - - - - -